diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile old mode 100644 new mode 100755 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json old mode 100644 new mode 100755 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.python-version b/.python-version old mode 100644 new mode 100755 diff --git a/.release-please-manifest.json b/.release-please-manifest.json old mode 100644 new mode 100755 index b0699969f..08e82c45c --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.14" + ".": "0.1.0-alpha.15" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml old mode 100644 new mode 100755 index 0169fbd25..f0fee8e9b --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 23 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-ccdd2f1f86705a3cc4e40bc294ca94e0e761f22bc8487955fc2a663c046688b5.yml +configured_endpoints: 24 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-2085d09cb7954db9bd300c0d93f1f08e25b69906011c0d65e899951880372ef1.yml diff --git a/Brewfile b/Brewfile old mode 100644 new mode 100755 diff --git a/CHANGELOG.md b/CHANGELOG.md index 143fd3ea8..94a00f222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 0.1.0-alpha.15 (2024-08-23) + +Full Changelog: [v0.1.0-alpha.14...v0.1.0-alpha.15](https://github.com/runloopai/api-client-python/compare/v0.1.0-alpha.14...v0.1.0-alpha.15) + +### Features + +* **api:** manual updates ([#117](https://github.com/runloopai/api-client-python/issues/117)) ([5222c74](https://github.com/runloopai/api-client-python/commit/5222c7462dae22befa4cbfe000635660c0b72070)) +* **api:** manual updates ([#118](https://github.com/runloopai/api-client-python/issues/118)) ([2801d62](https://github.com/runloopai/api-client-python/commit/2801d62df46e79a9054a4c32453b46436362aa2c)) +* **api:** OpenAPI spec update via Stainless API ([#106](https://github.com/runloopai/api-client-python/issues/106)) ([977e845](https://github.com/runloopai/api-client-python/commit/977e845bb31245f85aa00e1c0bdd091ed81967df)) +* **api:** OpenAPI spec update via Stainless API ([#110](https://github.com/runloopai/api-client-python/issues/110)) ([dc0bc88](https://github.com/runloopai/api-client-python/commit/dc0bc888d147dce2619d0e0f38897bd1df4372e6)) +* **api:** OpenAPI spec update via Stainless API ([#111](https://github.com/runloopai/api-client-python/issues/111)) ([82a1581](https://github.com/runloopai/api-client-python/commit/82a158114880b0d416ae4e9660926151daf1a60f)) +* **api:** OpenAPI spec update via Stainless API ([#112](https://github.com/runloopai/api-client-python/issues/112)) ([cfddae4](https://github.com/runloopai/api-client-python/commit/cfddae44be11039af98c8d6f570990351c552d9d)) +* **api:** OpenAPI spec update via Stainless API ([#113](https://github.com/runloopai/api-client-python/issues/113)) ([23d90e8](https://github.com/runloopai/api-client-python/commit/23d90e8d22775abcaf90e44fa7b9dc112d6d36ad)) +* **api:** OpenAPI spec update via Stainless API ([#114](https://github.com/runloopai/api-client-python/issues/114)) ([f754530](https://github.com/runloopai/api-client-python/commit/f7545300ecc975f555178729c987fa506d8c0dde)) +* **api:** OpenAPI spec update via Stainless API ([#115](https://github.com/runloopai/api-client-python/issues/115)) ([b5200de](https://github.com/runloopai/api-client-python/commit/b5200dedec44c8785daf06cb1acfa3b6909d8361)) +* **api:** OpenAPI spec update via Stainless API ([#120](https://github.com/runloopai/api-client-python/issues/120)) ([e432b64](https://github.com/runloopai/api-client-python/commit/e432b64ee28bf061878cba1bf76285d847cd3ce7)) + + +### Chores + +* **ci:** also run pydantic v1 tests ([#109](https://github.com/runloopai/api-client-python/issues/109)) ([23009f0](https://github.com/runloopai/api-client-python/commit/23009f032c59a5ab216c7602cabfe63253dd33b5)) +* **client:** fix parsing union responses when non-json is returned ([#108](https://github.com/runloopai/api-client-python/issues/108)) ([9133e9b](https://github.com/runloopai/api-client-python/commit/9133e9b87be8d363742b08f2f829699657982a6e)) + ## 0.1.0-alpha.14 (2024-08-16) Full Changelog: [v0.1.0-alpha.13...v0.1.0-alpha.14](https://github.com/runloopai/api-client-python/compare/v0.1.0-alpha.13...v0.1.0-alpha.14) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index c30cc313a..8dc4c7e51 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ Error codes are as followed: ### Retries -Certain errors are automatically retried 0 times by default, with a short exponential backoff. +Certain errors are automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors are all retried by default. diff --git a/SECURITY.md b/SECURITY.md old mode 100644 new mode 100755 diff --git a/api.md b/api.md old mode 100644 new mode 100755 index 6f52516ae..6bae20322 --- a/api.md +++ b/api.md @@ -49,9 +49,11 @@ Types: ```python from runloop_api_client.types import ( + DevboxAsyncExecutionDetailView, DevboxExecutionDetailView, DevboxListView, DevboxView, + DevboxCreateSSHKeyResponse, DevboxReadFileContentsResponse, DevboxUploadFileResponse, ) @@ -62,12 +64,13 @@ Methods: - client.devboxes.create(\*\*params) -> DevboxView - client.devboxes.retrieve(id) -> DevboxView - client.devboxes.list(\*\*params) -> DevboxListView -- client.devboxes.execute_sync(id, \*\*params) -> DevboxExecutionDetailView -- client.devboxes.read_file(id, \*\*params) -> DevboxExecutionDetailView +- client.devboxes.create_ssh_key(id) -> DevboxCreateSSHKeyResponse +- client.devboxes.execute_async(id, \*\*params) -> DevboxAsyncExecutionDetailView +- client.devboxes.execute_sync(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 +- client.devboxes.write_file(id, \*\*params) -> DevboxExecutionDetailView ## Logs @@ -81,6 +84,23 @@ Methods: - client.devboxes.logs.list(id) -> DevboxLogsListView +## Executions + +Types: + +```python +from runloop_api_client.types.devboxes import ( + DevboxAsyncExecutionDetailView, + DevboxExecutionDetailView, + DevboxLogsListView, +) +``` + +Methods: + +- client.devboxes.executions.execute_async(id, \*\*params) -> DevboxAsyncExecutionDetailView +- client.devboxes.executions.execute_sync(id, \*\*params) -> DevboxExecutionDetailView + # Functions Types: diff --git a/bin/check-release-environment b/bin/check-release-environment old mode 100644 new mode 100755 diff --git a/examples/.keep b/examples/.keep old mode 100644 new mode 100755 diff --git a/mypy.ini b/mypy.ini old mode 100644 new mode 100755 diff --git a/noxfile.py b/noxfile.py old mode 100644 new mode 100755 diff --git a/pyproject.toml b/pyproject.toml old mode 100644 new mode 100755 index 22380a1af..a0b32864f --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "runloop_api_client" -version = "0.1.0-alpha.14" +version = "0.1.0-alpha.15" description = "The official Python library for the runloop API" dynamic = ["readme"] license = "MIT" diff --git a/release-please-config.json b/release-please-config.json old mode 100644 new mode 100755 diff --git a/requirements-dev.lock b/requirements-dev.lock old mode 100644 new mode 100755 diff --git a/requirements.lock b/requirements.lock old mode 100644 new mode 100755 diff --git a/scripts/test b/scripts/test index b3ace9013..4fa5698b8 100755 --- a/scripts/test +++ b/scripts/test @@ -54,3 +54,6 @@ fi echo "==> Running tests" rye run pytest "$@" + +echo "==> Running Pydantic v1 tests" +rye run nox -s test-pydantic-v1 -- "$@" diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py old mode 100644 new mode 100755 diff --git a/src/runloop/lib/.keep b/src/runloop/lib/.keep old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/__init__.py b/src/runloop_api_client/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_base_client.py b/src/runloop_api_client/_base_client.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_client.py b/src/runloop_api_client/_client.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_compat.py b/src/runloop_api_client/_compat.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_constants.py b/src/runloop_api_client/_constants.py old mode 100644 new mode 100755 index 8e36fea12..a2ac3b6f3 --- a/src/runloop_api_client/_constants.py +++ b/src/runloop_api_client/_constants.py @@ -7,8 +7,8 @@ # default timeout is 1 minute DEFAULT_TIMEOUT = httpx.Timeout(timeout=60.0, connect=5.0) -DEFAULT_MAX_RETRIES = 0 +DEFAULT_MAX_RETRIES = 2 DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) -INITIAL_RETRY_DELAY = 1.0 -MAX_RETRY_DELAY = 5.0 +INITIAL_RETRY_DELAY = 0.5 +MAX_RETRY_DELAY = 8.0 diff --git a/src/runloop_api_client/_exceptions.py b/src/runloop_api_client/_exceptions.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_files.py b/src/runloop_api_client/_files.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_models.py b/src/runloop_api_client/_models.py old mode 100644 new mode 100755 index 5148d5a7b..d386eaa3a --- a/src/runloop_api_client/_models.py +++ b/src/runloop_api_client/_models.py @@ -380,6 +380,8 @@ def is_basemodel(type_: type) -> bool: def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: origin = get_origin(type_) or type_ + if not inspect.isclass(origin): + return False return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) diff --git a/src/runloop_api_client/_qs.py b/src/runloop_api_client/_qs.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_resource.py b/src/runloop_api_client/_resource.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_response.py b/src/runloop_api_client/_response.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_streaming.py b/src/runloop_api_client/_streaming.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_types.py b/src/runloop_api_client/_types.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/__init__.py b/src/runloop_api_client/_utils/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_logs.py b/src/runloop_api_client/_utils/_logs.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_proxy.py b/src/runloop_api_client/_utils/_proxy.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_reflection.py b/src/runloop_api_client/_utils/_reflection.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_streams.py b/src/runloop_api_client/_utils/_streams.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_sync.py b/src/runloop_api_client/_utils/_sync.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_transform.py b/src/runloop_api_client/_utils/_transform.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_typing.py b/src/runloop_api_client/_utils/_typing.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_utils/_utils.py b/src/runloop_api_client/_utils/_utils.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py old mode 100644 new mode 100755 index 70a399d94..b1688be6c --- a/src/runloop_api_client/_version.py +++ b/src/runloop_api_client/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "runloop_api_client" -__version__ = "0.1.0-alpha.14" # x-release-please-version +__version__ = "0.1.0-alpha.15" # x-release-please-version diff --git a/src/runloop_api_client/lib/.keep b/src/runloop_api_client/lib/.keep old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/py.typed b/src/runloop_api_client/py.typed old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/__init__.py b/src/runloop_api_client/resources/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/blueprints.py b/src/runloop_api_client/resources/blueprints.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/deployments.py b/src/runloop_api_client/resources/deployments.py new file mode 100755 index 000000000..70abbe237 --- /dev/null +++ b/src/runloop_api_client/resources/deployments.py @@ -0,0 +1,488 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import deployment_get_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import ( + maybe_transform, + async_maybe_transform, +) +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.deployment_get_response import DeploymentGetResponse +from ..types.deployment_logs_response import DeploymentLogsResponse +from ..types.deployment_tail_response import DeploymentTailResponse +from ..types.deployment_redeploy_response import DeploymentRedeployResponse +from ..types.deployment_retrieve_response import DeploymentRetrieveResponse + +__all__ = ["DeploymentsResource", "AsyncDeploymentsResource"] + + +class DeploymentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DeploymentsResourceWithRawResponse: + return DeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeploymentsResourceWithStreamingResponse: + return DeploymentsResourceWithStreamingResponse(self) + + def retrieve( + self, + deployment_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, + ) -> DeploymentRetrieveResponse: + """ + Get details of a deployment + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return self._get( + f"/v1/deployments/{deployment_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRetrieveResponse, + ) + + def get( + self, + *, + limit: str | NotGiven = NOT_GIVEN, + starting_after: 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, + ) -> DeploymentGetResponse: + """ + Get list of all deployments for the authenticated user. + + Args: + limit: Page Limit + + starting_after: Load the next page starting after the given token. + + 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 + """ + return self._get( + "/v1/deployments", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "starting_after": starting_after, + }, + deployment_get_params.DeploymentGetParams, + ), + ), + cast_to=DeploymentGetResponse, + ) + + def logs( + self, + deployment_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, + ) -> DeploymentLogsResponse: + """ + Get list of all logs from a deployment. + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return self._get( + f"/v1/deployments/{deployment_id}/logs", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentLogsResponse, + ) + + def redeploy( + self, + deployment_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, + ) -> DeploymentRedeployResponse: + """ + Creates a deployment for a previously deployed version. + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return self._post( + f"/v1/deployments/{deployment_id}/redeploy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRedeployResponse, + ) + + def tail( + self, + deployment_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, + ) -> DeploymentTailResponse: + """ + Tails the logs for the given deployment with SSE streaming + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return self._get( + f"/v1/deployments/{deployment_id}/logs/tail", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentTailResponse, + ) + + +class AsyncDeploymentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDeploymentsResourceWithRawResponse: + return AsyncDeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeploymentsResourceWithStreamingResponse: + return AsyncDeploymentsResourceWithStreamingResponse(self) + + async def retrieve( + self, + deployment_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, + ) -> DeploymentRetrieveResponse: + """ + Get details of a deployment + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return await self._get( + f"/v1/deployments/{deployment_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRetrieveResponse, + ) + + async def get( + self, + *, + limit: str | NotGiven = NOT_GIVEN, + starting_after: 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, + ) -> DeploymentGetResponse: + """ + Get list of all deployments for the authenticated user. + + Args: + limit: Page Limit + + starting_after: Load the next page starting after the given token. + + 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 + """ + return await self._get( + "/v1/deployments", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "limit": limit, + "starting_after": starting_after, + }, + deployment_get_params.DeploymentGetParams, + ), + ), + cast_to=DeploymentGetResponse, + ) + + async def logs( + self, + deployment_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, + ) -> DeploymentLogsResponse: + """ + Get list of all logs from a deployment. + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return await self._get( + f"/v1/deployments/{deployment_id}/logs", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentLogsResponse, + ) + + async def redeploy( + self, + deployment_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, + ) -> DeploymentRedeployResponse: + """ + Creates a deployment for a previously deployed version. + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return await self._post( + f"/v1/deployments/{deployment_id}/redeploy", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRedeployResponse, + ) + + async def tail( + self, + deployment_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, + ) -> DeploymentTailResponse: + """ + Tails the logs for the given deployment with SSE streaming + + 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 deployment_id: + raise ValueError(f"Expected a non-empty value for `deployment_id` but received {deployment_id!r}") + return await self._get( + f"/v1/deployments/{deployment_id}/logs/tail", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentTailResponse, + ) + + +class DeploymentsResourceWithRawResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.retrieve = to_raw_response_wrapper( + deployments.retrieve, + ) + self.get = to_raw_response_wrapper( + deployments.get, + ) + self.logs = to_raw_response_wrapper( + deployments.logs, + ) + self.redeploy = to_raw_response_wrapper( + deployments.redeploy, + ) + self.tail = to_raw_response_wrapper( + deployments.tail, + ) + + +class AsyncDeploymentsResourceWithRawResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.retrieve = async_to_raw_response_wrapper( + deployments.retrieve, + ) + self.get = async_to_raw_response_wrapper( + deployments.get, + ) + self.logs = async_to_raw_response_wrapper( + deployments.logs, + ) + self.redeploy = async_to_raw_response_wrapper( + deployments.redeploy, + ) + self.tail = async_to_raw_response_wrapper( + deployments.tail, + ) + + +class DeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.retrieve = to_streamed_response_wrapper( + deployments.retrieve, + ) + self.get = to_streamed_response_wrapper( + deployments.get, + ) + self.logs = to_streamed_response_wrapper( + deployments.logs, + ) + self.redeploy = to_streamed_response_wrapper( + deployments.redeploy, + ) + self.tail = to_streamed_response_wrapper( + deployments.tail, + ) + + +class AsyncDeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.retrieve = async_to_streamed_response_wrapper( + deployments.retrieve, + ) + self.get = async_to_streamed_response_wrapper( + deployments.get, + ) + self.logs = async_to_streamed_response_wrapper( + deployments.logs, + ) + self.redeploy = async_to_streamed_response_wrapper( + deployments.redeploy, + ) + self.tail = async_to_streamed_response_wrapper( + deployments.tail, + ) diff --git a/src/runloop_api_client/resources/devboxes/__init__.py b/src/runloop_api_client/resources/devboxes/__init__.py old mode 100644 new mode 100755 index 814a1ca00..ec7c746ac --- a/src/runloop_api_client/resources/devboxes/__init__.py +++ b/src/runloop_api_client/resources/devboxes/__init__.py @@ -16,6 +16,14 @@ DevboxesResourceWithStreamingResponse, AsyncDevboxesResourceWithStreamingResponse, ) +from .executions import ( + ExecutionsResource, + AsyncExecutionsResource, + ExecutionsResourceWithRawResponse, + AsyncExecutionsResourceWithRawResponse, + ExecutionsResourceWithStreamingResponse, + AsyncExecutionsResourceWithStreamingResponse, +) __all__ = [ "LogsResource", @@ -24,6 +32,12 @@ "AsyncLogsResourceWithRawResponse", "LogsResourceWithStreamingResponse", "AsyncLogsResourceWithStreamingResponse", + "ExecutionsResource", + "AsyncExecutionsResource", + "ExecutionsResourceWithRawResponse", + "AsyncExecutionsResourceWithRawResponse", + "ExecutionsResourceWithStreamingResponse", + "AsyncExecutionsResourceWithStreamingResponse", "DevboxesResource", "AsyncDevboxesResource", "DevboxesResourceWithRawResponse", diff --git a/src/runloop_api_client/resources/devboxes/devboxes.py b/src/runloop_api_client/resources/devboxes/devboxes.py old mode 100644 new mode 100755 index 9bdd4b784..a45032569 --- a/src/runloop_api_client/resources/devboxes/devboxes.py +++ b/src/runloop_api_client/resources/devboxes/devboxes.py @@ -17,10 +17,10 @@ from ...types import ( devbox_list_params, devbox_create_params, - devbox_read_file_params, devbox_write_file_params, devbox_upload_file_params, devbox_execute_sync_params, + devbox_execute_async_params, devbox_read_file_contents_params, ) from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes @@ -31,6 +31,14 @@ async_maybe_transform, ) from ..._compat import cached_property +from .executions import ( + ExecutionsResource, + AsyncExecutionsResource, + ExecutionsResourceWithRawResponse, + AsyncExecutionsResourceWithRawResponse, + ExecutionsResourceWithStreamingResponse, + AsyncExecutionsResourceWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( to_raw_response_wrapper, @@ -41,7 +49,9 @@ from ..._base_client import make_request_options from ...types.devbox_view import DevboxView from ...types.devbox_list_view import DevboxListView -from ...types.devbox_execution_detail_view import DevboxExecutionDetailView +from ...types.devbox_create_ssh_key_response import DevboxCreateSSHKeyResponse +from ...types.devboxes.devbox_execution_detail_view import DevboxExecutionDetailView +from ...types.devboxes.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView __all__ = ["DevboxesResource", "AsyncDevboxesResource"] @@ -51,6 +61,10 @@ class DevboxesResource(SyncAPIResource): def logs(self) -> LogsResource: return LogsResource(self._client) + @cached_property + def executions(self) -> ExecutionsResource: + return ExecutionsResource(self._client) + @cached_property def with_raw_response(self) -> DevboxesResourceWithRawResponse: return DevboxesResourceWithRawResponse(self) @@ -68,6 +82,7 @@ def create( environment_variables: Dict[str, str] | NotGiven = NOT_GIVEN, file_mounts: Dict[str, str] | NotGiven = NOT_GIVEN, launch_parameters: devbox_create_params.LaunchParameters | NotGiven = NOT_GIVEN, + metadata: Dict[str, str] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, setup_commands: List[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -99,6 +114,8 @@ def create( launch_parameters: Parameters to configure the resources and launch time behavior of the Devbox. + metadata: User defined metadata to attach to the devbox for organization. + name: (Optional) A user specified name to give the Devbox. setup_commands: (Optional) List of commands needed to set up your Devbox. Examples might include @@ -123,6 +140,7 @@ def create( "environment_variables": environment_variables, "file_mounts": file_mounts, "launch_parameters": launch_parameters, + "metadata": metadata, "name": name, "setup_commands": setup_commands, }, @@ -220,7 +238,40 @@ def list( cast_to=DevboxListView, ) - def execute_sync( + def create_ssh_key( + self, + 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, + ) -> DevboxCreateSSHKeyResponse: + """ + Create an SSH key for a devbox by id. + + 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}/create_ssh_key", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxCreateSSHKeyResponse, + ) + + def execute_async( self, id: str, *, @@ -231,9 +282,9 @@ def execute_sync( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> DevboxExecutionDetailView: + ) -> DevboxAsyncExecutionDetailView: """ - Synchronously execute a command on a devbox + Asynchronously execute a command on a devbox Args: command: The command to execute on the Devbox. @@ -249,19 +300,19 @@ def execute_sync( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._post( - f"/v1/devboxes/{id}/execute_sync", - body=maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams), + f"/v1/devboxes/{id}/executions/execute_async", + body=maybe_transform({"command": command}, devbox_execute_async_params.DevboxExecuteAsyncParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=DevboxExecutionDetailView, + cast_to=DevboxAsyncExecutionDetailView, ) - def read_file( + def execute_sync( self, id: str, *, - file_path: str | NotGiven = NOT_GIVEN, + command: 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, @@ -270,10 +321,10 @@ def read_file( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> DevboxExecutionDetailView: """ - Read file contents from a file on given Devbox. + Synchronously execute a command on a devbox Args: - file_path: The path of the file to read. + command: The command to execute on the Devbox. extra_headers: Send extra headers @@ -286,8 +337,8 @@ def read_file( if not id: raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") return self._post( - f"/v1/devboxes/{id}/read_file", - body=maybe_transform({"file_path": file_path}, devbox_read_file_params.DevboxReadFileParams), + f"/v1/devboxes/{id}/execute_sync", + body=maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -468,6 +519,10 @@ class AsyncDevboxesResource(AsyncAPIResource): def logs(self) -> AsyncLogsResource: return AsyncLogsResource(self._client) + @cached_property + def executions(self) -> AsyncExecutionsResource: + return AsyncExecutionsResource(self._client) + @cached_property def with_raw_response(self) -> AsyncDevboxesResourceWithRawResponse: return AsyncDevboxesResourceWithRawResponse(self) @@ -485,6 +540,7 @@ async def create( environment_variables: Dict[str, str] | NotGiven = NOT_GIVEN, file_mounts: Dict[str, str] | NotGiven = NOT_GIVEN, launch_parameters: devbox_create_params.LaunchParameters | NotGiven = NOT_GIVEN, + metadata: Dict[str, str] | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, setup_commands: List[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -516,6 +572,8 @@ async def create( launch_parameters: Parameters to configure the resources and launch time behavior of the Devbox. + metadata: User defined metadata to attach to the devbox for organization. + name: (Optional) A user specified name to give the Devbox. setup_commands: (Optional) List of commands needed to set up your Devbox. Examples might include @@ -540,6 +598,7 @@ async def create( "environment_variables": environment_variables, "file_mounts": file_mounts, "launch_parameters": launch_parameters, + "metadata": metadata, "name": name, "setup_commands": setup_commands, }, @@ -637,7 +696,40 @@ async def list( cast_to=DevboxListView, ) - async def execute_sync( + async def create_ssh_key( + self, + 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, + ) -> DevboxCreateSSHKeyResponse: + """ + Create an SSH key for a devbox by id. + + 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}/create_ssh_key", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxCreateSSHKeyResponse, + ) + + async def execute_async( self, id: str, *, @@ -648,9 +740,9 @@ async def execute_sync( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> DevboxExecutionDetailView: + ) -> DevboxAsyncExecutionDetailView: """ - Synchronously execute a command on a devbox + Asynchronously execute a command on a devbox Args: command: The command to execute on the Devbox. @@ -666,19 +758,21 @@ async def execute_sync( 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}/execute_sync", - body=await async_maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams), + f"/v1/devboxes/{id}/executions/execute_async", + body=await async_maybe_transform( + {"command": command}, devbox_execute_async_params.DevboxExecuteAsyncParams + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=DevboxExecutionDetailView, + cast_to=DevboxAsyncExecutionDetailView, ) - async def read_file( + async def execute_sync( self, id: str, *, - file_path: str | NotGiven = NOT_GIVEN, + command: 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, @@ -687,10 +781,10 @@ async def read_file( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> DevboxExecutionDetailView: """ - Read file contents from a file on given Devbox. + Synchronously execute a command on a devbox Args: - file_path: The path of the file to read. + command: The command to execute on the Devbox. extra_headers: Send extra headers @@ -703,8 +797,8 @@ async def read_file( 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}/read_file", - body=await async_maybe_transform({"file_path": file_path}, devbox_read_file_params.DevboxReadFileParams), + f"/v1/devboxes/{id}/execute_sync", + body=await async_maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -893,12 +987,15 @@ def __init__(self, devboxes: DevboxesResource) -> None: self.list = to_raw_response_wrapper( devboxes.list, ) + self.create_ssh_key = to_raw_response_wrapper( + devboxes.create_ssh_key, + ) + self.execute_async = to_raw_response_wrapper( + devboxes.execute_async, + ) self.execute_sync = to_raw_response_wrapper( devboxes.execute_sync, ) - self.read_file = to_raw_response_wrapper( - devboxes.read_file, - ) self.read_file_contents = to_raw_response_wrapper( devboxes.read_file_contents, ) @@ -916,6 +1013,10 @@ def __init__(self, devboxes: DevboxesResource) -> None: def logs(self) -> LogsResourceWithRawResponse: return LogsResourceWithRawResponse(self._devboxes.logs) + @cached_property + def executions(self) -> ExecutionsResourceWithRawResponse: + return ExecutionsResourceWithRawResponse(self._devboxes.executions) + class AsyncDevboxesResourceWithRawResponse: def __init__(self, devboxes: AsyncDevboxesResource) -> None: @@ -930,12 +1031,15 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: self.list = async_to_raw_response_wrapper( devboxes.list, ) + self.create_ssh_key = async_to_raw_response_wrapper( + devboxes.create_ssh_key, + ) + self.execute_async = async_to_raw_response_wrapper( + devboxes.execute_async, + ) self.execute_sync = async_to_raw_response_wrapper( devboxes.execute_sync, ) - self.read_file = async_to_raw_response_wrapper( - devboxes.read_file, - ) self.read_file_contents = async_to_raw_response_wrapper( devboxes.read_file_contents, ) @@ -953,6 +1057,10 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: def logs(self) -> AsyncLogsResourceWithRawResponse: return AsyncLogsResourceWithRawResponse(self._devboxes.logs) + @cached_property + def executions(self) -> AsyncExecutionsResourceWithRawResponse: + return AsyncExecutionsResourceWithRawResponse(self._devboxes.executions) + class DevboxesResourceWithStreamingResponse: def __init__(self, devboxes: DevboxesResource) -> None: @@ -967,12 +1075,15 @@ def __init__(self, devboxes: DevboxesResource) -> None: self.list = to_streamed_response_wrapper( devboxes.list, ) + self.create_ssh_key = to_streamed_response_wrapper( + devboxes.create_ssh_key, + ) + self.execute_async = to_streamed_response_wrapper( + devboxes.execute_async, + ) self.execute_sync = to_streamed_response_wrapper( devboxes.execute_sync, ) - self.read_file = to_streamed_response_wrapper( - devboxes.read_file, - ) self.read_file_contents = to_streamed_response_wrapper( devboxes.read_file_contents, ) @@ -990,6 +1101,10 @@ def __init__(self, devboxes: DevboxesResource) -> None: def logs(self) -> LogsResourceWithStreamingResponse: return LogsResourceWithStreamingResponse(self._devboxes.logs) + @cached_property + def executions(self) -> ExecutionsResourceWithStreamingResponse: + return ExecutionsResourceWithStreamingResponse(self._devboxes.executions) + class AsyncDevboxesResourceWithStreamingResponse: def __init__(self, devboxes: AsyncDevboxesResource) -> None: @@ -1004,12 +1119,15 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: self.list = async_to_streamed_response_wrapper( devboxes.list, ) + self.create_ssh_key = async_to_streamed_response_wrapper( + devboxes.create_ssh_key, + ) + self.execute_async = async_to_streamed_response_wrapper( + devboxes.execute_async, + ) self.execute_sync = async_to_streamed_response_wrapper( devboxes.execute_sync, ) - self.read_file = async_to_streamed_response_wrapper( - devboxes.read_file, - ) self.read_file_contents = async_to_streamed_response_wrapper( devboxes.read_file_contents, ) @@ -1026,3 +1144,7 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None: @cached_property def logs(self) -> AsyncLogsResourceWithStreamingResponse: return AsyncLogsResourceWithStreamingResponse(self._devboxes.logs) + + @cached_property + def executions(self) -> AsyncExecutionsResourceWithStreamingResponse: + return AsyncExecutionsResourceWithStreamingResponse(self._devboxes.executions) diff --git a/src/runloop_api_client/resources/devboxes/executions.py b/src/runloop_api_client/resources/devboxes/executions.py new file mode 100755 index 000000000..7886822a3 --- /dev/null +++ b/src/runloop_api_client/resources/devboxes/executions.py @@ -0,0 +1,245 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + 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.devbox_execution_detail_view import DevboxExecutionDetailView +from ...types.devboxes.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView + +__all__ = ["ExecutionsResource", "AsyncExecutionsResource"] + + +class ExecutionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExecutionsResourceWithRawResponse: + return ExecutionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExecutionsResourceWithStreamingResponse: + return ExecutionsResourceWithStreamingResponse(self) + + def execute_async( + self, + id: str, + *, + command: 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: + """ + Asynchronously execute a command on a devbox + + Args: + command: The command to execute on the Devbox. + + 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}/executions/execute_async", + body=maybe_transform({"command": command}, execution_execute_async_params.ExecutionExecuteAsyncParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + + def execute_sync( + self, + id: str, + *, + command: 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, + ) -> DevboxExecutionDetailView: + """ + Synchronously execute a command on a devbox + + Args: + command: The command to execute on the Devbox. + + 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}/execute_sync", + body=maybe_transform({"command": command}, execution_execute_sync_params.ExecutionExecuteSyncParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxExecutionDetailView, + ) + + +class AsyncExecutionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExecutionsResourceWithRawResponse: + return AsyncExecutionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExecutionsResourceWithStreamingResponse: + return AsyncExecutionsResourceWithStreamingResponse(self) + + async def execute_async( + self, + id: str, + *, + command: 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: + """ + Asynchronously execute a command on a devbox + + Args: + command: The command to execute on the Devbox. + + 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}/executions/execute_async", + body=await async_maybe_transform( + {"command": command}, execution_execute_async_params.ExecutionExecuteAsyncParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxAsyncExecutionDetailView, + ) + + async def execute_sync( + self, + id: str, + *, + command: 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, + ) -> DevboxExecutionDetailView: + """ + Synchronously execute a command on a devbox + + Args: + command: The command to execute on the Devbox. + + 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}/execute_sync", + body=await async_maybe_transform( + {"command": command}, execution_execute_sync_params.ExecutionExecuteSyncParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DevboxExecutionDetailView, + ) + + +class ExecutionsResourceWithRawResponse: + def __init__(self, executions: ExecutionsResource) -> None: + self._executions = executions + + self.execute_async = to_raw_response_wrapper( + executions.execute_async, + ) + self.execute_sync = to_raw_response_wrapper( + executions.execute_sync, + ) + + +class AsyncExecutionsResourceWithRawResponse: + def __init__(self, executions: AsyncExecutionsResource) -> None: + self._executions = executions + + self.execute_async = async_to_raw_response_wrapper( + executions.execute_async, + ) + self.execute_sync = async_to_raw_response_wrapper( + executions.execute_sync, + ) + + +class ExecutionsResourceWithStreamingResponse: + def __init__(self, executions: ExecutionsResource) -> None: + self._executions = executions + + self.execute_async = to_streamed_response_wrapper( + executions.execute_async, + ) + self.execute_sync = to_streamed_response_wrapper( + executions.execute_sync, + ) + + +class AsyncExecutionsResourceWithStreamingResponse: + def __init__(self, executions: AsyncExecutionsResource) -> None: + self._executions = executions + + self.execute_async = async_to_streamed_response_wrapper( + executions.execute_async, + ) + self.execute_sync = async_to_streamed_response_wrapper( + executions.execute_sync, + ) diff --git a/src/runloop_api_client/resources/devboxes/logs.py b/src/runloop_api_client/resources/devboxes/logs.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/functions/__init__.py b/src/runloop_api_client/resources/functions/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/functions/functions.py b/src/runloop_api_client/resources/functions/functions.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/functions/invocations.py b/src/runloop_api_client/resources/functions/invocations.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/projects/__init__.py b/src/runloop_api_client/resources/projects/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/projects/logs.py b/src/runloop_api_client/resources/projects/logs.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/resources/projects/projects.py b/src/runloop_api_client/resources/projects/projects.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py old mode 100644 new mode 100755 index 616342b9e..c24af1bd1 --- a/src/runloop_api_client/types/__init__.py +++ b/src/runloop_api_client/types/__init__.py @@ -20,16 +20,16 @@ from .code_mount_parameters import CodeMountParameters as CodeMountParameters from .blueprint_preview_view import BlueprintPreviewView as BlueprintPreviewView from .blueprint_create_params import BlueprintCreateParams as BlueprintCreateParams -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 +from .devbox_execute_async_params import DevboxExecuteAsyncParams as DevboxExecuteAsyncParams from .function_invoke_sync_params import FunctionInvokeSyncParams as FunctionInvokeSyncParams -from .devbox_execution_detail_view import DevboxExecutionDetailView as DevboxExecutionDetailView from .function_invoke_async_params import FunctionInvokeAsyncParams as FunctionInvokeAsyncParams from .blueprint_build_logs_list_view import BlueprintBuildLogsListView as BlueprintBuildLogsListView +from .devbox_create_ssh_key_response import DevboxCreateSSHKeyResponse as DevboxCreateSSHKeyResponse from .devbox_read_file_contents_params import DevboxReadFileContentsParams as DevboxReadFileContentsParams from .devbox_read_file_contents_response import DevboxReadFileContentsResponse as DevboxReadFileContentsResponse diff --git a/src/runloop_api_client/types/blueprint_build_log.py b/src/runloop_api_client/types/blueprint_build_log.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_build_logs_list_view.py b/src/runloop_api_client/types/blueprint_build_logs_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_build_parameters.py b/src/runloop_api_client/types/blueprint_build_parameters.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_create_params.py b/src/runloop_api_client/types/blueprint_create_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_list_params.py b/src/runloop_api_client/types/blueprint_list_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_list_view.py b/src/runloop_api_client/types/blueprint_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_preview_params.py b/src/runloop_api_client/types/blueprint_preview_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_preview_view.py b/src/runloop_api_client/types/blueprint_preview_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/blueprint_view.py b/src/runloop_api_client/types/blueprint_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/code_mount_parameters.py b/src/runloop_api_client/types/code_mount_parameters.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/code_mount_parameters_param.py b/src/runloop_api_client/types/code_mount_parameters_param.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/deployment_get_params.py b/src/runloop_api_client/types/deployment_get_params.py new file mode 100755 index 000000000..c4c564b6b --- /dev/null +++ b/src/runloop_api_client/types/deployment_get_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["DeploymentGetParams"] + + +class DeploymentGetParams(TypedDict, total=False): + limit: str + """Page Limit""" + + starting_after: str + """Load the next page starting after the given token.""" diff --git a/src/runloop_api_client/types/deployment_get_response.py b/src/runloop_api_client/types/deployment_get_response.py new file mode 100755 index 000000000..e291ac77f --- /dev/null +++ b/src/runloop_api_client/types/deployment_get_response.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentGetResponse", "Deployment"] + + +class Deployment(BaseModel): + id: Optional[str] = None + """ID of the deployment.""" + + deploy_commit_message: Optional[str] = None + """Associated Commit Message""" + + deploy_commit_sha: Optional[str] = None + """Associated Commit Sha""" + + deploy_commit_time_ms: Optional[int] = None + """Associated Commit Time""" + + deploy_end_time_ms: Optional[int] = None + """Time the Deploy completed (Unix timestamp milliseconds).""" + + deploy_start_time_ms: Optional[int] = None + """Time the Deploy was started (Unix timestamp milliseconds).""" + + deployed_functions: Optional[List[str]] = None + """The list of deployed functions.""" + + failure_code: Optional[str] = None + """ + Failure code (generic_failure | git_clone_failure | not_runloop_repo | + secrets_failure | provision_failure | runtime_failure). Only set on + deploy_failed. + """ + + failure_message: Optional[str] = None + """Failure message""" + + project_name: Optional[str] = None + """Project name associated with the deployment.""" + + redeploy_of: Optional[str] = None + """ID of original deployment this is redeployment for.""" + + status: Optional[Literal["scheduled", "skipped", "in_progress", "failed", "deployed"]] = None + """Status of the deploy.""" + + +class DeploymentGetResponse(BaseModel): + deployments: Optional[List[Deployment]] = None + """List of projects matching given query.""" + + has_more: Optional[bool] = None + + total_count: Optional[int] = None diff --git a/src/runloop_api_client/types/deployment_logs_response.py b/src/runloop_api_client/types/deployment_logs_response.py new file mode 100755 index 000000000..ccd2ec3da --- /dev/null +++ b/src/runloop_api_client/types/deployment_logs_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["DeploymentLogsResponse", "Log"] + + +class Log(BaseModel): + level: Optional[str] = None + """Log line severity level.""" + + message: Optional[str] = None + """Log line message.""" + + timestamp_ms: Optional[int] = None + """Time of log (Unix timestamp milliseconds).""" + + +class DeploymentLogsResponse(BaseModel): + deployment_id: Optional[str] = None + """ID of the given deployment.""" + + logs: Optional[List[Log]] = None + """List of logs for the given deployment.""" diff --git a/src/runloop_api_client/types/deployment_redeploy_response.py b/src/runloop_api_client/types/deployment_redeploy_response.py new file mode 100755 index 000000000..679938a26 --- /dev/null +++ b/src/runloop_api_client/types/deployment_redeploy_response.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentRedeployResponse"] + + +class DeploymentRedeployResponse(BaseModel): + id: Optional[str] = None + """ID of the deployment.""" + + deploy_commit_message: Optional[str] = None + """Associated Commit Message""" + + deploy_commit_sha: Optional[str] = None + """Associated Commit Sha""" + + deploy_commit_time_ms: Optional[int] = None + """Associated Commit Time""" + + deploy_end_time_ms: Optional[int] = None + """Time the Deploy completed (Unix timestamp milliseconds).""" + + deploy_start_time_ms: Optional[int] = None + """Time the Deploy was started (Unix timestamp milliseconds).""" + + deployed_functions: Optional[List[str]] = None + """The list of deployed functions.""" + + failure_code: Optional[str] = None + """ + Failure code (generic_failure | git_clone_failure | not_runloop_repo | + secrets_failure | provision_failure | runtime_failure). Only set on + deploy_failed. + """ + + failure_message: Optional[str] = None + """Failure message""" + + project_name: Optional[str] = None + """Project name associated with the deployment.""" + + redeploy_of: Optional[str] = None + """ID of original deployment this is redeployment for.""" + + status: Optional[Literal["scheduled", "skipped", "in_progress", "failed", "deployed"]] = None + """Status of the deploy.""" diff --git a/src/runloop_api_client/types/deployment_retrieve_response.py b/src/runloop_api_client/types/deployment_retrieve_response.py new file mode 100755 index 000000000..a2fa1bf41 --- /dev/null +++ b/src/runloop_api_client/types/deployment_retrieve_response.py @@ -0,0 +1,50 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentRetrieveResponse"] + + +class DeploymentRetrieveResponse(BaseModel): + id: Optional[str] = None + """ID of the deployment.""" + + deploy_commit_message: Optional[str] = None + """Associated Commit Message""" + + deploy_commit_sha: Optional[str] = None + """Associated Commit Sha""" + + deploy_commit_time_ms: Optional[int] = None + """Associated Commit Time""" + + deploy_end_time_ms: Optional[int] = None + """Time the Deploy completed (Unix timestamp milliseconds).""" + + deploy_start_time_ms: Optional[int] = None + """Time the Deploy was started (Unix timestamp milliseconds).""" + + deployed_functions: Optional[List[str]] = None + """The list of deployed functions.""" + + failure_code: Optional[str] = None + """ + Failure code (generic_failure | git_clone_failure | not_runloop_repo | + secrets_failure | provision_failure | runtime_failure). Only set on + deploy_failed. + """ + + failure_message: Optional[str] = None + """Failure message""" + + project_name: Optional[str] = None + """Project name associated with the deployment.""" + + redeploy_of: Optional[str] = None + """ID of original deployment this is redeployment for.""" + + status: Optional[Literal["scheduled", "skipped", "in_progress", "failed", "deployed"]] = None + """Status of the deploy.""" diff --git a/src/runloop_api_client/types/deployment_tail_response.py b/src/runloop_api_client/types/deployment_tail_response.py new file mode 100755 index 000000000..afd26fc86 --- /dev/null +++ b/src/runloop_api_client/types/deployment_tail_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["DeploymentTailResponse", "Log"] + + +class Log(BaseModel): + level: Optional[str] = None + """Log line severity level.""" + + message: Optional[str] = None + """Log line message.""" + + timestamp_ms: Optional[int] = None + """Time of log (Unix timestamp milliseconds).""" + + +class DeploymentTailResponse(BaseModel): + deployment_id: Optional[str] = None + """ID of the given deployment.""" + + logs: Optional[List[Log]] = None + """List of logs for the given deployment.""" diff --git a/src/runloop_api_client/types/devbox_create_params.py b/src/runloop_api_client/types/devbox_create_params.py old mode 100644 new mode 100755 index 80cd31ef3..61bb1453a --- a/src/runloop_api_client/types/devbox_create_params.py +++ b/src/runloop_api_client/types/devbox_create_params.py @@ -40,6 +40,9 @@ class DevboxCreateParams(TypedDict, total=False): launch_parameters: LaunchParameters """Parameters to configure the resources and launch time behavior of the Devbox.""" + metadata: Dict[str, str] + """User defined metadata to attach to the devbox for organization.""" + name: str """(Optional) A user specified name to give the Devbox.""" diff --git a/src/runloop_api_client/types/devbox_create_ssh_key_response.py b/src/runloop_api_client/types/devbox_create_ssh_key_response.py new file mode 100755 index 000000000..3f8c7c366 --- /dev/null +++ b/src/runloop_api_client/types/devbox_create_ssh_key_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["DevboxCreateSSHKeyResponse"] + + +class DevboxCreateSSHKeyResponse(BaseModel): + id: Optional[str] = None + """The id of the Devbox.""" + + ssh_private_key: Optional[str] = None + """The ssh private key, in PEM format.""" + + url: Optional[str] = None + """The url of the Devbox.""" diff --git a/src/runloop_api_client/types/devbox_execute_async_params.py b/src/runloop_api_client/types/devbox_execute_async_params.py new file mode 100755 index 000000000..9f5a7a8f4 --- /dev/null +++ b/src/runloop_api_client/types/devbox_execute_async_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["DevboxExecuteAsyncParams"] + + +class DevboxExecuteAsyncParams(TypedDict, total=False): + command: str + """The command to execute on the Devbox.""" diff --git a/src/runloop_api_client/types/devbox_execute_sync_params.py b/src/runloop_api_client/types/devbox_execute_sync_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_execution_detail_view.py b/src/runloop_api_client/types/devbox_execution_detail_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_list_params.py b/src/runloop_api_client/types/devbox_list_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_list_response.py b/src/runloop_api_client/types/devbox_list_response.py new file mode 100755 index 000000000..d56c67f9f --- /dev/null +++ b/src/runloop_api_client/types/devbox_list_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .devbox_view import DevboxView + +__all__ = ["DevboxListResponse"] + + +class DevboxListResponse(BaseModel): + devboxes: Optional[List[DevboxView]] = None + """List of devboxes matching filter.""" + + has_more: Optional[bool] = None + + total_count: Optional[int] = None diff --git a/src/runloop_api_client/types/devbox_list_view.py b/src/runloop_api_client/types/devbox_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_read_file_contents_params.py b/src/runloop_api_client/types/devbox_read_file_contents_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_read_file_contents_response.py b/src/runloop_api_client/types/devbox_read_file_contents_response.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_read_file_params.py b/src/runloop_api_client/types/devbox_read_file_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_upload_file_params.py b/src/runloop_api_client/types/devbox_upload_file_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devbox_view.py b/src/runloop_api_client/types/devbox_view.py old mode 100644 new mode 100755 index 724ce3372..e2433cc10 --- a/src/runloop_api_client/types/devbox_view.py +++ b/src/runloop_api_client/types/devbox_view.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Optional from typing_extensions import Literal from .._models import BaseModel @@ -21,12 +21,18 @@ class DevboxView(BaseModel): end_time_ms: Optional[int] = None """The time the Devbox finished execution (Unix timestamp milliseconds).""" + failure_reason: Optional[Literal["out_of_memory", "out_of_disk", "execution_failed"]] = None + """The failure reason if the Devbox failed, if any.""" + initiator_id: Optional[str] = None """The initiator ID of the devbox.""" initiator_type: Optional[Literal["unknown", "api", "invocation"]] = None """The initiator of the devbox.""" + metadata: Optional[Dict[str, str]] = None + """The user defined Devbox metadata.""" + name: Optional[str] = None """The name of the Devbox.""" diff --git a/src/runloop_api_client/types/devbox_write_file_params.py b/src/runloop_api_client/types/devbox_write_file_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devboxes/__init__.py b/src/runloop_api_client/types/devboxes/__init__.py old mode 100644 new mode 100755 index 7baebfdd7..cdfd4886e --- a/src/runloop_api_client/types/devboxes/__init__.py +++ b/src/runloop_api_client/types/devboxes/__init__.py @@ -3,3 +3,7 @@ from __future__ import annotations from .devbox_logs_list_view import DevboxLogsListView as DevboxLogsListView +from .devbox_execution_detail_view import DevboxExecutionDetailView as DevboxExecutionDetailView +from .execution_execute_sync_params import ExecutionExecuteSyncParams as ExecutionExecuteSyncParams +from .execution_execute_async_params import ExecutionExecuteAsyncParams as ExecutionExecuteAsyncParams +from .devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView as DevboxAsyncExecutionDetailView diff --git a/src/runloop_api_client/types/devboxes/devbox_async_execution_detail_view.py b/src/runloop_api_client/types/devboxes/devbox_async_execution_detail_view.py new file mode 100755 index 000000000..ea60ca7f0 --- /dev/null +++ b/src/runloop_api_client/types/devboxes/devbox_async_execution_detail_view.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["DevboxAsyncExecutionDetailView"] + + +class DevboxAsyncExecutionDetailView(BaseModel): + devbox_id: Optional[str] = None + """Devbox id where command was executed.""" + + execution_id: Optional[str] = None + """Ephemeral id of the execution in progress.""" + + exit_status: Optional[int] = None + """Exit code of command execution. + + This field will remain unset until the execution has completed. + """ + + status: Optional[Literal["running", "success", "failure", "canceled"]] = None + """Current status of the execution.""" + + stderr: Optional[str] = None + """Standard error generated by command. + + This field will remain unset until the execution has completed. + """ + + stdout: Optional[str] = None + """Standard out generated by command. + + This field will remain unset until the execution has completed. + """ diff --git a/src/runloop_api_client/types/devboxes/devbox_execution_detail_view.py b/src/runloop_api_client/types/devboxes/devbox_execution_detail_view.py new file mode 100755 index 000000000..eadd60b1d --- /dev/null +++ b/src/runloop_api_client/types/devboxes/devbox_execution_detail_view.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["DevboxExecutionDetailView"] + + +class DevboxExecutionDetailView(BaseModel): + devbox_id: Optional[str] = None + """Devbox id where command was executed.""" + + exit_status: Optional[int] = None + """Exit status of command execution.""" + + stderr: Optional[str] = None + """Standard error generated by command.""" + + stdout: Optional[str] = None + """Standard out generated by command.""" diff --git a/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py b/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/devboxes/execution_execute_async_params.py b/src/runloop_api_client/types/devboxes/execution_execute_async_params.py new file mode 100755 index 000000000..7878309c5 --- /dev/null +++ b/src/runloop_api_client/types/devboxes/execution_execute_async_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ExecutionExecuteAsyncParams"] + + +class ExecutionExecuteAsyncParams(TypedDict, total=False): + command: str + """The command to execute on the Devbox.""" diff --git a/src/runloop_api_client/types/devboxes/execution_execute_sync_params.py b/src/runloop_api_client/types/devboxes/execution_execute_sync_params.py new file mode 100755 index 000000000..392794ac9 --- /dev/null +++ b/src/runloop_api_client/types/devboxes/execution_execute_sync_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ExecutionExecuteSyncParams"] + + +class ExecutionExecuteSyncParams(TypedDict, total=False): + command: str + """The command to execute on the Devbox.""" 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 100755 index 000000000..3cafe88fe --- /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): + id: Required[str] + + command: str + """The command to execute on the Devbox.""" diff --git a/src/runloop_api_client/types/function_invoke_async_params.py b/src/runloop_api_client/types/function_invoke_async_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/function_invoke_sync_params.py b/src/runloop_api_client/types/function_invoke_sync_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/function_list_view.py b/src/runloop_api_client/types/function_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/functions/__init__.py b/src/runloop_api_client/types/functions/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/functions/function_invocation_list_view.py b/src/runloop_api_client/types/functions/function_invocation_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/functions/invocation_list_params.py b/src/runloop_api_client/types/functions/invocation_list_params.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/functions/invocation_logs_response.py b/src/runloop_api_client/types/functions/invocation_logs_response.py new file mode 100755 index 000000000..240b32c4a --- /dev/null +++ b/src/runloop_api_client/types/functions/invocation_logs_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["InvocationLogsResponse", "Log"] + + +class Log(BaseModel): + level: Optional[str] = None + """Log line severity level.""" + + message: Optional[str] = None + """Log line message.""" + + timestamp_ms: Optional[int] = None + """Time of log (Unix timestamp milliseconds).""" + + +class InvocationLogsResponse(BaseModel): + invocation_id: Optional[str] = None + """ID of the invocation.""" + + logs: Optional[List[Log]] = None + """List of logs for the given invocation.""" diff --git a/src/runloop_api_client/types/project_list_view.py b/src/runloop_api_client/types/project_list_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/projects/__init__.py b/src/runloop_api_client/types/projects/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/resource_size.py b/src/runloop_api_client/types/resource_size.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/shared/__init__.py b/src/runloop_api_client/types/shared/__init__.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/shared/function_invocation_execution_detail_view.py b/src/runloop_api_client/types/shared/function_invocation_execution_detail_view.py old mode 100644 new mode 100755 diff --git a/src/runloop_api_client/types/shared/project_logs_view.py b/src/runloop_api_client/types/shared/project_logs_view.py old mode 100644 new mode 100755 diff --git a/tests/__init__.py b/tests/__init__.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/__init__.py b/tests/api_resources/__init__.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/devboxes/__init__.py b/tests/api_resources/devboxes/__init__.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/devboxes/test_executions.py b/tests/api_resources/devboxes/test_executions.py new file mode 100755 index 000000000..540e32771 --- /dev/null +++ b/tests/api_resources/devboxes/test_executions.py @@ -0,0 +1,209 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from runloop_api_client import Runloop, AsyncRunloop +from runloop_api_client.types.devboxes import ( + DevboxExecutionDetailView, + DevboxAsyncExecutionDetailView, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExecutions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_execute_async(self, client: Runloop) -> None: + execution = client.devboxes.executions.execute_async( + id="id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_method_execute_async_with_all_params(self, client: Runloop) -> None: + execution = client.devboxes.executions.execute_async( + id="id", + command="command", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_raw_response_execute_async(self, client: Runloop) -> None: + response = client.devboxes.executions.with_raw_response.execute_async( + id="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_execute_async(self, client: Runloop) -> None: + with client.devboxes.executions.with_streaming_response.execute_async( + id="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_execute_async(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.devboxes.executions.with_raw_response.execute_async( + id="", + ) + + @parametrize + def test_method_execute_sync(self, client: Runloop) -> None: + execution = client.devboxes.executions.execute_sync( + id="id", + ) + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_method_execute_sync_with_all_params(self, client: Runloop) -> None: + execution = client.devboxes.executions.execute_sync( + id="id", + command="command", + ) + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_raw_response_execute_sync(self, client: Runloop) -> None: + response = client.devboxes.executions.with_raw_response.execute_sync( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + def test_streaming_response_execute_sync(self, client: Runloop) -> None: + with client.devboxes.executions.with_streaming_response.execute_sync( + id="id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_execute_sync(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.devboxes.executions.with_raw_response.execute_sync( + id="", + ) + + +class TestAsyncExecutions: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_execute_async(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.execute_async( + id="id", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_method_execute_async_with_all_params(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.execute_async( + id="id", + command="command", + ) + assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_raw_response_execute_async(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.executions.with_raw_response.execute_async( + id="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_execute_async(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.executions.with_streaming_response.execute_async( + id="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_execute_async(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.devboxes.executions.with_raw_response.execute_async( + id="", + ) + + @parametrize + async def test_method_execute_sync(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.execute_sync( + id="id", + ) + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_method_execute_sync_with_all_params(self, async_client: AsyncRunloop) -> None: + execution = await async_client.devboxes.executions.execute_sync( + id="id", + command="command", + ) + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_raw_response_execute_sync(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.executions.with_raw_response.execute_sync( + id="id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(DevboxExecutionDetailView, execution, path=["response"]) + + @parametrize + async def test_streaming_response_execute_sync(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.executions.with_streaming_response.execute_sync( + id="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(DevboxExecutionDetailView, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_execute_sync(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.devboxes.executions.with_raw_response.execute_sync( + id="", + ) diff --git a/tests/api_resources/devboxes/test_logs.py b/tests/api_resources/devboxes/test_logs.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/functions/__init__.py b/tests/api_resources/functions/__init__.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/functions/test_invocations.py b/tests/api_resources/functions/test_invocations.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/projects/__init__.py b/tests/api_resources/projects/__init__.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/projects/test_logs.py b/tests/api_resources/projects/test_logs.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/test_blueprints.py b/tests/api_resources/test_blueprints.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/test_deployments.py b/tests/api_resources/test_deployments.py new file mode 100755 index 000000000..1c1c11f74 --- /dev/null +++ b/tests/api_resources/test_deployments.py @@ -0,0 +1,406 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from runloop_api_client import Runloop, AsyncRunloop +from runloop_api_client.types import ( + DeploymentGetResponse, + DeploymentLogsResponse, + DeploymentTailResponse, + DeploymentRedeployResponse, + DeploymentRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDeployments: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_retrieve(self, client: Runloop) -> None: + deployment = client.deployments.retrieve( + "deployment_id", + ) + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @parametrize + def test_raw_response_retrieve(self, client: Runloop) -> None: + response = client.deployments.with_raw_response.retrieve( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @parametrize + def test_streaming_response_retrieve(self, client: Runloop) -> None: + with client.deployments.with_streaming_response.retrieve( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentRetrieveResponse, deployment, 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 `deployment_id` but received ''"): + client.deployments.with_raw_response.retrieve( + "", + ) + + @parametrize + def test_method_get(self, client: Runloop) -> None: + deployment = client.deployments.get() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + def test_method_get_with_all_params(self, client: Runloop) -> None: + deployment = client.deployments.get( + limit="limit", + starting_after="starting_after", + ) + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + def test_raw_response_get(self, client: Runloop) -> None: + response = client.deployments.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + def test_streaming_response_get(self, client: Runloop) -> None: + with client.deployments.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_method_logs(self, client: Runloop) -> None: + deployment = client.deployments.logs( + "deployment_id", + ) + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + @parametrize + def test_raw_response_logs(self, client: Runloop) -> None: + response = client.deployments.with_raw_response.logs( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + @parametrize + def test_streaming_response_logs(self, client: Runloop) -> None: + with client.deployments.with_streaming_response.logs( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_logs(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + client.deployments.with_raw_response.logs( + "", + ) + + @parametrize + def test_method_redeploy(self, client: Runloop) -> None: + deployment = client.deployments.redeploy( + "deployment_id", + ) + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + @parametrize + def test_raw_response_redeploy(self, client: Runloop) -> None: + response = client.deployments.with_raw_response.redeploy( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + @parametrize + def test_streaming_response_redeploy(self, client: Runloop) -> None: + with client.deployments.with_streaming_response.redeploy( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_redeploy(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + client.deployments.with_raw_response.redeploy( + "", + ) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + def test_method_tail(self, client: Runloop) -> None: + deployment = client.deployments.tail( + "deployment_id", + ) + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + def test_raw_response_tail(self, client: Runloop) -> None: + response = client.deployments.with_raw_response.tail( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + def test_streaming_response_tail(self, client: Runloop) -> None: + with client.deployments.with_streaming_response.tail( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + def test_path_params_tail(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + client.deployments.with_raw_response.tail( + "", + ) + + +class TestAsyncDeployments: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_retrieve(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.retrieve( + "deployment_id", + ) + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncRunloop) -> None: + response = await async_client.deployments.with_raw_response.retrieve( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncRunloop) -> None: + async with async_client.deployments.with_streaming_response.retrieve( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentRetrieveResponse, deployment, 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 `deployment_id` but received ''"): + await async_client.deployments.with_raw_response.retrieve( + "", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.get() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + async def test_method_get_with_all_params(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.get( + limit="limit", + starting_after="starting_after", + ) + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + async def test_raw_response_get(self, async_client: AsyncRunloop) -> None: + response = await async_client.deployments.with_raw_response.get() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_get(self, async_client: AsyncRunloop) -> None: + async with async_client.deployments.with_streaming_response.get() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentGetResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_method_logs(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.logs( + "deployment_id", + ) + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + @parametrize + async def test_raw_response_logs(self, async_client: AsyncRunloop) -> None: + response = await async_client.deployments.with_raw_response.logs( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_logs(self, async_client: AsyncRunloop) -> None: + async with async_client.deployments.with_streaming_response.logs( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentLogsResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_logs(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + await async_client.deployments.with_raw_response.logs( + "", + ) + + @parametrize + async def test_method_redeploy(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.redeploy( + "deployment_id", + ) + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + @parametrize + async def test_raw_response_redeploy(self, async_client: AsyncRunloop) -> None: + response = await async_client.deployments.with_raw_response.redeploy( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + @parametrize + async def test_streaming_response_redeploy(self, async_client: AsyncRunloop) -> None: + async with async_client.deployments.with_streaming_response.redeploy( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentRedeployResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_redeploy(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + await async_client.deployments.with_raw_response.redeploy( + "", + ) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + async def test_method_tail(self, async_client: AsyncRunloop) -> None: + deployment = await async_client.deployments.tail( + "deployment_id", + ) + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + async def test_raw_response_tail(self, async_client: AsyncRunloop) -> None: + response = await async_client.deployments.with_raw_response.tail( + "deployment_id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + async def test_streaming_response_tail(self, async_client: AsyncRunloop) -> None: + async with async_client.deployments.with_streaming_response.tail( + "deployment_id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentTailResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="cannot test text/event-stream") + @parametrize + async def test_path_params_tail(self, async_client: AsyncRunloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `deployment_id` but received ''"): + await async_client.deployments.with_raw_response.tail( + "", + ) diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py old mode 100644 new mode 100755 index 5edb2c25e..80fce2549 --- a/tests/api_resources/test_devboxes.py +++ b/tests/api_resources/test_devboxes.py @@ -12,8 +12,9 @@ from runloop_api_client.types import ( DevboxView, DevboxListView, - DevboxExecutionDetailView, + DevboxCreateSSHKeyResponse, ) +from runloop_api_client.types.devboxes import DevboxExecutionDetailView, DevboxAsyncExecutionDetailView base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -39,6 +40,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "launch_commands": ["string", "string", "string"], "resource_size_request": "MINI", }, + metadata={"foo": "string"}, name="name", setup_commands=["string", "string", "string"], ) @@ -137,69 +139,107 @@ def test_streaming_response_list(self, client: Runloop) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_method_execute_sync(self, client: Runloop) -> None: - devbox = client.devboxes.execute_sync( + def test_method_create_ssh_key(self, client: Runloop) -> None: + devbox = client.devboxes.create_ssh_key( + "id", + ) + assert_matches_type(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + @parametrize + def test_raw_response_create_ssh_key(self, client: Runloop) -> None: + response = client.devboxes.with_raw_response.create_ssh_key( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + devbox = response.parse() + assert_matches_type(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + @parametrize + def test_streaming_response_create_ssh_key(self, client: Runloop) -> None: + with client.devboxes.with_streaming_response.create_ssh_key( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + devbox = response.parse() + assert_matches_type(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create_ssh_key(self, client: Runloop) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.devboxes.with_raw_response.create_ssh_key( + "", + ) + + @parametrize + def test_method_execute_async(self, client: Runloop) -> None: + devbox = client.devboxes.execute_async( id="id", ) - assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - def test_method_execute_sync_with_all_params(self, client: Runloop) -> None: - devbox = client.devboxes.execute_sync( + def test_method_execute_async_with_all_params(self, client: Runloop) -> None: + devbox = client.devboxes.execute_async( id="id", command="command", ) - assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - def test_raw_response_execute_sync(self, client: Runloop) -> None: - response = client.devboxes.with_raw_response.execute_sync( + def test_raw_response_execute_async(self, client: Runloop) -> None: + response = client.devboxes.with_raw_response.execute_async( id="id", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" devbox = response.parse() - assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - def test_streaming_response_execute_sync(self, client: Runloop) -> None: - with client.devboxes.with_streaming_response.execute_sync( + def test_streaming_response_execute_async(self, client: Runloop) -> None: + with client.devboxes.with_streaming_response.execute_async( 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(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_execute_sync(self, client: Runloop) -> None: + def test_path_params_execute_async(self, client: Runloop) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.devboxes.with_raw_response.execute_sync( + client.devboxes.with_raw_response.execute_async( id="", ) @parametrize - def test_method_read_file(self, client: Runloop) -> None: - devbox = client.devboxes.read_file( + def test_method_execute_sync(self, client: Runloop) -> None: + devbox = client.devboxes.execute_sync( id="id", ) assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - def test_method_read_file_with_all_params(self, client: Runloop) -> None: - devbox = client.devboxes.read_file( + def test_method_execute_sync_with_all_params(self, client: Runloop) -> None: + devbox = client.devboxes.execute_sync( id="id", - file_path="file_path", + command="command", ) assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - def test_raw_response_read_file(self, client: Runloop) -> None: - response = client.devboxes.with_raw_response.read_file( + def test_raw_response_execute_sync(self, client: Runloop) -> None: + response = client.devboxes.with_raw_response.execute_sync( id="id", ) @@ -209,8 +249,8 @@ def test_raw_response_read_file(self, client: Runloop) -> None: assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - def test_streaming_response_read_file(self, client: Runloop) -> None: - with client.devboxes.with_streaming_response.read_file( + def test_streaming_response_execute_sync(self, client: Runloop) -> None: + with client.devboxes.with_streaming_response.execute_sync( id="id", ) as response: assert not response.is_closed @@ -222,9 +262,9 @@ def test_streaming_response_read_file(self, client: Runloop) -> None: assert cast(Any, response.is_closed) is True @parametrize - def test_path_params_read_file(self, client: Runloop) -> None: + def test_path_params_execute_sync(self, client: Runloop) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.devboxes.with_raw_response.read_file( + client.devboxes.with_raw_response.execute_sync( id="", ) @@ -428,6 +468,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "launch_commands": ["string", "string", "string"], "resource_size_request": "MINI", }, + metadata={"foo": "string"}, name="name", setup_commands=["string", "string", "string"], ) @@ -526,69 +567,107 @@ async def test_streaming_response_list(self, async_client: AsyncRunloop) -> None assert cast(Any, response.is_closed) is True @parametrize - async def test_method_execute_sync(self, async_client: AsyncRunloop) -> None: - devbox = await async_client.devboxes.execute_sync( + async def test_method_create_ssh_key(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.create_ssh_key( + "id", + ) + assert_matches_type(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + @parametrize + async def test_raw_response_create_ssh_key(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.with_raw_response.create_ssh_key( + "id", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + devbox = await response.parse() + assert_matches_type(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + @parametrize + async def test_streaming_response_create_ssh_key(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.with_streaming_response.create_ssh_key( + "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(DevboxCreateSSHKeyResponse, devbox, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create_ssh_key(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.create_ssh_key( + "", + ) + + @parametrize + async def test_method_execute_async(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.execute_async( id="id", ) - assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_method_execute_sync_with_all_params(self, async_client: AsyncRunloop) -> None: - devbox = await async_client.devboxes.execute_sync( + async def test_method_execute_async_with_all_params(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.execute_async( id="id", command="command", ) - assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_raw_response_execute_sync(self, async_client: AsyncRunloop) -> None: - response = await async_client.devboxes.with_raw_response.execute_sync( + async def test_raw_response_execute_async(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.with_raw_response.execute_async( 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(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_streaming_response_execute_sync(self, async_client: AsyncRunloop) -> None: - async with async_client.devboxes.with_streaming_response.execute_sync( + async def test_streaming_response_execute_async(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.with_streaming_response.execute_async( 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(DevboxExecutionDetailView, devbox, path=["response"]) + assert_matches_type(DevboxAsyncExecutionDetailView, devbox, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_execute_sync(self, async_client: AsyncRunloop) -> None: + async def test_path_params_execute_async(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.execute_sync( + await async_client.devboxes.with_raw_response.execute_async( id="", ) @parametrize - async def test_method_read_file(self, async_client: AsyncRunloop) -> None: - devbox = await async_client.devboxes.read_file( + async def test_method_execute_sync(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.execute_sync( id="id", ) assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_method_read_file_with_all_params(self, async_client: AsyncRunloop) -> None: - devbox = await async_client.devboxes.read_file( + async def test_method_execute_sync_with_all_params(self, async_client: AsyncRunloop) -> None: + devbox = await async_client.devboxes.execute_sync( id="id", - file_path="file_path", + command="command", ) assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_raw_response_read_file(self, async_client: AsyncRunloop) -> None: - response = await async_client.devboxes.with_raw_response.read_file( + async def test_raw_response_execute_sync(self, async_client: AsyncRunloop) -> None: + response = await async_client.devboxes.with_raw_response.execute_sync( id="id", ) @@ -598,8 +677,8 @@ async def test_raw_response_read_file(self, async_client: AsyncRunloop) -> None: assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"]) @parametrize - async def test_streaming_response_read_file(self, async_client: AsyncRunloop) -> None: - async with async_client.devboxes.with_streaming_response.read_file( + async def test_streaming_response_execute_sync(self, async_client: AsyncRunloop) -> None: + async with async_client.devboxes.with_streaming_response.execute_sync( id="id", ) as response: assert not response.is_closed @@ -611,9 +690,9 @@ async def test_streaming_response_read_file(self, async_client: AsyncRunloop) -> assert cast(Any, response.is_closed) is True @parametrize - async def test_path_params_read_file(self, async_client: AsyncRunloop) -> None: + async def test_path_params_execute_sync(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.read_file( + await async_client.devboxes.with_raw_response.execute_sync( id="", ) diff --git a/tests/api_resources/test_functions.py b/tests/api_resources/test_functions.py old mode 100644 new mode 100755 diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py old mode 100644 new mode 100755 diff --git a/tests/conftest.py b/tests/conftest.py old mode 100644 new mode 100755 diff --git a/tests/sample_file.txt b/tests/sample_file.txt old mode 100644 new mode 100755 diff --git a/tests/test_client.py b/tests/test_client.py old mode 100644 new mode 100755 index a9738496a..ab10be034 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -87,7 +87,7 @@ def test_copy_default_options(self) -> None: # options that have a default are overridden correctly copied = self.client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 0 + assert self.client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 @@ -706,20 +706,20 @@ class Model(BaseModel): "remaining_retries,retry_after,timeout", [ [3, "20", 20], - [3, "0", 1], - [3, "-10", 1], + [3, "0", 0.5], + [3, "-10", 0.5], [3, "60", 60], - [3, "61", 1], + [3, "61", 0.5], [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], - [3, "Fri, 29 Sep 2023 16:26:37 GMT", 1], - [3, "Fri, 29 Sep 2023 16:26:27 GMT", 1], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], - [3, "Fri, 29 Sep 2023 16:27:38 GMT", 1], - [3, "99999999999999999999999999999999999", 1], - [3, "Zun, 29 Sep 2023 16:26:27 GMT", 1], - [3, "", 1], - [2, "", 1 * 2.0], - [1, "", 1 * 4.0], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -729,7 +729,7 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 1 * 0.875) # pyright: ignore[reportUnknownMemberType] + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("runloop_api_client._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -820,7 +820,7 @@ def test_copy_default_options(self) -> None: # options that have a default are overridden correctly copied = self.client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 0 + assert self.client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 @@ -1442,20 +1442,20 @@ class Model(BaseModel): "remaining_retries,retry_after,timeout", [ [3, "20", 20], - [3, "0", 1], - [3, "-10", 1], + [3, "0", 0.5], + [3, "-10", 0.5], [3, "60", 60], - [3, "61", 1], + [3, "61", 0.5], [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], - [3, "Fri, 29 Sep 2023 16:26:37 GMT", 1], - [3, "Fri, 29 Sep 2023 16:26:27 GMT", 1], + [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], + [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], - [3, "Fri, 29 Sep 2023 16:27:38 GMT", 1], - [3, "99999999999999999999999999999999999", 1], - [3, "Zun, 29 Sep 2023 16:26:27 GMT", 1], - [3, "", 1], - [2, "", 1 * 2.0], - [1, "", 1 * 4.0], + [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], + [3, "99999999999999999999999999999999999", 0.5], + [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], + [3, "", 0.5], + [2, "", 0.5 * 2.0], + [1, "", 0.5 * 4.0], ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) @@ -1466,7 +1466,7 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 1 * 0.875) # pyright: ignore[reportUnknownMemberType] + assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("runloop_api_client._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py old mode 100644 new mode 100755 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py old mode 100644 new mode 100755 diff --git a/tests/test_files.py b/tests/test_files.py old mode 100644 new mode 100755 diff --git a/tests/test_models.py b/tests/test_models.py old mode 100644 new mode 100755 diff --git a/tests/test_qs.py b/tests/test_qs.py old mode 100644 new mode 100755 diff --git a/tests/test_required_args.py b/tests/test_required_args.py old mode 100644 new mode 100755 diff --git a/tests/test_response.py b/tests/test_response.py old mode 100644 new mode 100755 index d24372998..849a519e5 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,5 +1,5 @@ import json -from typing import List, cast +from typing import Any, List, Union, cast from typing_extensions import Annotated import httpx @@ -188,3 +188,40 @@ async def test_async_response_parse_annotated_type(async_client: AsyncRunloop) - ) assert obj.foo == "hello!" assert obj.bar == 2 + + +class OtherModel(BaseModel): + a: str + + +@pytest.mark.parametrize("client", [False], indirect=True) # loose validation +def test_response_parse_expect_model_union_non_json_content(client: Runloop) -> None: + response = APIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" + + +@pytest.mark.asyncio +@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation +async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncRunloop) -> None: + response = AsyncAPIResponse( + raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), + client=async_client, + stream=False, + stream_cls=None, + cast_to=str, + options=FinalRequestOptions.construct(method="get", url="/foo"), + ) + + obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel])) + assert isinstance(obj, str) + assert obj == "foo" diff --git a/tests/test_streaming.py b/tests/test_streaming.py old mode 100644 new mode 100755 diff --git a/tests/test_transform.py b/tests/test_transform.py old mode 100644 new mode 100755 diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py old mode 100644 new mode 100755 diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py old mode 100644 new mode 100755 diff --git a/tests/utils.py b/tests/utils.py old mode 100644 new mode 100755