From 83e4f2c26f02a7df56917e993af1e1d85ba241e6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:10:30 +0000 Subject: [PATCH 01/23] chore(tests): run tests in parallel --- pyproject.toml | 3 ++- requirements-dev.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 4c9fc23..ce8b48d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ dev-dependencies = [ "importlib-metadata>=6.7.0", "rich>=13.7.1", "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -125,7 +126,7 @@ replacement = '[\1](https://github.com/onkernel/kernel-python-sdk/tree/main/\g<2 [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index efd90ea..f40d985 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -30,6 +30,8 @@ distro==1.8.0 exceptiongroup==1.2.2 # via anyio # via pytest +execnet==2.1.1 + # via pytest-xdist filelock==3.12.4 # via virtualenv h11==0.14.0 @@ -72,7 +74,9 @@ pygments==2.18.0 pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio + # via pytest-xdist pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 From 007934910a1ec8e17a6be821feacef9b42a2c142 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:35:04 +0000 Subject: [PATCH 02/23] fix(client): correctly parse binary response | stream --- src/kernel/_base_client.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/kernel/_base_client.py b/src/kernel/_base_client.py index 785adea..c86e919 100644 --- a/src/kernel/_base_client.py +++ b/src/kernel/_base_client.py @@ -1071,7 +1071,14 @@ def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1574,7 +1581,14 @@ async def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") From 7bd810a49eb26d4a62e924b25e52c22ec3e5dfde Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 19:42:26 +0000 Subject: [PATCH 03/23] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d654666..d2422bd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 11 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-4502c65bef0843a6ae96d23bba075433af6bab49b55b544b1522f63e7881c00c.yml -openapi_spec_hash: 3e67b77bbc8cd6155b8f66f3271f2643 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-fa302aa17477431aaa82682fe71bdbb519270815fdc917477e1d7e606411be50.yml +openapi_spec_hash: 291cb0245ba582712900f0fb5cf44ee4 config_hash: c6bab7ac8da570a5abbcfb19db119b6b From 2e69f9952537d5fb4fc4ea7502a567c07ff3c6ab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 19:47:29 +0000 Subject: [PATCH 04/23] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index d2422bd..8826a54 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 11 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-fa302aa17477431aaa82682fe71bdbb519270815fdc917477e1d7e606411be50.yml -openapi_spec_hash: 291cb0245ba582712900f0fb5cf44ee4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-e622f6886b1153050eb4ee9fda37fff8b36b38b52e5d247ea172deb2594bf9d6.yml +openapi_spec_hash: 3fa294f57c68b34e526a52bdd86eb562 config_hash: c6bab7ac8da570a5abbcfb19db119b6b From 496e5cd31745446c16234120f9299be4a9830bb5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 19:59:19 +0000 Subject: [PATCH 05/23] feat(api): update via SDK Studio --- .stats.yml | 8 +- api.md | 18 + src/kernel/_client.py | 10 +- src/kernel/resources/__init__.py | 14 + src/kernel/resources/deployments.py | 407 ++++++++++++++++++ src/kernel/types/__init__.py | 4 + src/kernel/types/deployment_create_params.py | 33 ++ .../types/deployment_create_response.py | 35 ++ .../types/deployment_follow_response.py | 129 ++++++ .../types/deployment_retrieve_response.py | 35 ++ tests/api_resources/test_deployments.py | 304 +++++++++++++ 11 files changed, 992 insertions(+), 5 deletions(-) create mode 100644 src/kernel/resources/deployments.py create mode 100644 src/kernel/types/deployment_create_params.py create mode 100644 src/kernel/types/deployment_create_response.py create mode 100644 src/kernel/types/deployment_follow_response.py create mode 100644 src/kernel/types/deployment_retrieve_response.py create mode 100644 tests/api_resources/test_deployments.py diff --git a/.stats.yml b/.stats.yml index 8826a54..f34bfc3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 11 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-e622f6886b1153050eb4ee9fda37fff8b36b38b52e5d247ea172deb2594bf9d6.yml -openapi_spec_hash: 3fa294f57c68b34e526a52bdd86eb562 -config_hash: c6bab7ac8da570a5abbcfb19db119b6b +configured_endpoints: 14 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-d2dfee8d576aa73f6075e6da61228571cb2e844b969a06067e34e43eb7898554.yml +openapi_spec_hash: 9981744bf9c27426cdf721f7b27cf093 +config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/api.md b/api.md index cbacba5..db76da3 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,21 @@ +# Deployments + +Types: + +```python +from kernel.types import ( + DeploymentCreateResponse, + DeploymentRetrieveResponse, + DeploymentFollowResponse, +) +``` + +Methods: + +- client.deployments.create(\*\*params) -> DeploymentCreateResponse +- client.deployments.retrieve(id) -> DeploymentRetrieveResponse +- client.deployments.follow(id) -> DeploymentFollowResponse + # Apps Types: diff --git a/src/kernel/_client.py b/src/kernel/_client.py index bf6fbb4..084d2a5 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -21,7 +21,7 @@ ) from ._utils import is_given, get_async_library from ._version import __version__ -from .resources import browsers +from .resources import browsers, deployments from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import KernelError, APIStatusError from ._base_client import ( @@ -50,6 +50,7 @@ class Kernel(SyncAPIClient): + deployments: deployments.DeploymentsResource apps: apps.AppsResource browsers: browsers.BrowsersResource with_raw_response: KernelWithRawResponse @@ -133,6 +134,7 @@ def __init__( _strict_response_validation=_strict_response_validation, ) + self.deployments = deployments.DeploymentsResource(self) self.apps = apps.AppsResource(self) self.browsers = browsers.BrowsersResource(self) self.with_raw_response = KernelWithRawResponse(self) @@ -246,6 +248,7 @@ def _make_status_error( class AsyncKernel(AsyncAPIClient): + deployments: deployments.AsyncDeploymentsResource apps: apps.AsyncAppsResource browsers: browsers.AsyncBrowsersResource with_raw_response: AsyncKernelWithRawResponse @@ -329,6 +332,7 @@ def __init__( _strict_response_validation=_strict_response_validation, ) + self.deployments = deployments.AsyncDeploymentsResource(self) self.apps = apps.AsyncAppsResource(self) self.browsers = browsers.AsyncBrowsersResource(self) self.with_raw_response = AsyncKernelWithRawResponse(self) @@ -443,24 +447,28 @@ def _make_status_error( class KernelWithRawResponse: def __init__(self, client: Kernel) -> None: + self.deployments = deployments.DeploymentsResourceWithRawResponse(client.deployments) self.apps = apps.AppsResourceWithRawResponse(client.apps) self.browsers = browsers.BrowsersResourceWithRawResponse(client.browsers) class AsyncKernelWithRawResponse: def __init__(self, client: AsyncKernel) -> None: + self.deployments = deployments.AsyncDeploymentsResourceWithRawResponse(client.deployments) self.apps = apps.AsyncAppsResourceWithRawResponse(client.apps) self.browsers = browsers.AsyncBrowsersResourceWithRawResponse(client.browsers) class KernelWithStreamedResponse: def __init__(self, client: Kernel) -> None: + self.deployments = deployments.DeploymentsResourceWithStreamingResponse(client.deployments) self.apps = apps.AppsResourceWithStreamingResponse(client.apps) self.browsers = browsers.BrowsersResourceWithStreamingResponse(client.browsers) class AsyncKernelWithStreamedResponse: def __init__(self, client: AsyncKernel) -> None: + self.deployments = deployments.AsyncDeploymentsResourceWithStreamingResponse(client.deployments) self.apps = apps.AsyncAppsResourceWithStreamingResponse(client.apps) self.browsers = browsers.AsyncBrowsersResourceWithStreamingResponse(client.browsers) diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index 647bde6..f65d1db 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -16,8 +16,22 @@ BrowsersResourceWithStreamingResponse, AsyncBrowsersResourceWithStreamingResponse, ) +from .deployments import ( + DeploymentsResource, + AsyncDeploymentsResource, + DeploymentsResourceWithRawResponse, + AsyncDeploymentsResourceWithRawResponse, + DeploymentsResourceWithStreamingResponse, + AsyncDeploymentsResourceWithStreamingResponse, +) __all__ = [ + "DeploymentsResource", + "AsyncDeploymentsResource", + "DeploymentsResourceWithRawResponse", + "AsyncDeploymentsResourceWithRawResponse", + "DeploymentsResourceWithStreamingResponse", + "AsyncDeploymentsResourceWithStreamingResponse", "AppsResource", "AsyncAppsResource", "AppsResourceWithRawResponse", diff --git a/src/kernel/resources/deployments.py b/src/kernel/resources/deployments.py new file mode 100644 index 0000000..6442ff0 --- /dev/null +++ b/src/kernel/resources/deployments.py @@ -0,0 +1,407 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, Dict, Mapping, cast +from typing_extensions import Literal + +import httpx + +from ..types import deployment_create_params +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven, FileTypes +from .._utils import extract_files, maybe_transform, deepcopy_minimal, 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 .._streaming import Stream, AsyncStream +from .._base_client import make_request_options +from ..types.deployment_create_response import DeploymentCreateResponse +from ..types.deployment_follow_response import DeploymentFollowResponse +from ..types.deployment_retrieve_response import DeploymentRetrieveResponse + +__all__ = ["DeploymentsResource", "AsyncDeploymentsResource"] + + +class DeploymentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return DeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return DeploymentsResourceWithStreamingResponse(self) + + def create( + self, + *, + entrypoint_rel_path: str, + file: FileTypes, + env_vars: Dict[str, str] | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + region: Literal["aws.us-east-1a"] | NotGiven = NOT_GIVEN, + version: 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, + ) -> DeploymentCreateResponse: + """ + Create a new deployment. + + Args: + entrypoint_rel_path: Relative path to the entrypoint of the application + + file: ZIP file containing the application source directory + + env_vars: Map of environment variables to set for the deployed application. Each key-value + pair represents an environment variable. + + force: Allow overwriting an existing app version + + region: Region for deployment. Currently we only support "aws.us-east-1a" + + version: Version of the application. Can be any string. + + 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 + """ + body = deepcopy_minimal( + { + "entrypoint_rel_path": entrypoint_rel_path, + "file": file, + "env_vars": env_vars, + "force": force, + "region": region, + "version": version, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return self._post( + "/deployments", + body=maybe_transform(body, deployment_create_params.DeploymentCreateParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentCreateResponse, + ) + + def retrieve( + 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, + ) -> DeploymentRetrieveResponse: + """ + Get information about a deployment's status. + + 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._get( + f"/deployments/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRetrieveResponse, + ) + + def follow( + 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, + ) -> Stream[DeploymentFollowResponse]: + """ + Establishes a Server-Sent Events (SSE) stream that delivers real-time logs and + status updates for a deployment. The stream terminates automatically once the + deployment reaches a terminal state. + + 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}") + extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} + return self._get( + f"/deployments/{id}/events", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, DeploymentFollowResponse + ), # Union types cannot be passed in as arguments in the type system + stream=True, + stream_cls=Stream[DeploymentFollowResponse], + ) + + +class AsyncDeploymentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDeploymentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncDeploymentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeploymentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/onkernel/kernel-python-sdk#with_streaming_response + """ + return AsyncDeploymentsResourceWithStreamingResponse(self) + + async def create( + self, + *, + entrypoint_rel_path: str, + file: FileTypes, + env_vars: Dict[str, str] | NotGiven = NOT_GIVEN, + force: bool | NotGiven = NOT_GIVEN, + region: Literal["aws.us-east-1a"] | NotGiven = NOT_GIVEN, + version: 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, + ) -> DeploymentCreateResponse: + """ + Create a new deployment. + + Args: + entrypoint_rel_path: Relative path to the entrypoint of the application + + file: ZIP file containing the application source directory + + env_vars: Map of environment variables to set for the deployed application. Each key-value + pair represents an environment variable. + + force: Allow overwriting an existing app version + + region: Region for deployment. Currently we only support "aws.us-east-1a" + + version: Version of the application. Can be any string. + + 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 + """ + body = deepcopy_minimal( + { + "entrypoint_rel_path": entrypoint_rel_path, + "file": file, + "env_vars": env_vars, + "force": force, + "region": region, + "version": version, + } + ) + files = extract_files(cast(Mapping[str, object], body), paths=[["file"]]) + # It should be noted that the actual Content-Type header that will be + # sent to the server will contain a `boundary` parameter, e.g. + # multipart/form-data; boundary=---abc-- + extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})} + return await self._post( + "/deployments", + body=await async_maybe_transform(body, deployment_create_params.DeploymentCreateParams), + files=files, + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentCreateResponse, + ) + + async def retrieve( + 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, + ) -> DeploymentRetrieveResponse: + """ + Get information about a deployment's status. + + 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._get( + f"/deployments/{id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeploymentRetrieveResponse, + ) + + async def follow( + 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, + ) -> AsyncStream[DeploymentFollowResponse]: + """ + Establishes a Server-Sent Events (SSE) stream that delivers real-time logs and + status updates for a deployment. The stream terminates automatically once the + deployment reaches a terminal state. + + 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}") + extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} + return await self._get( + f"/deployments/{id}/events", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, DeploymentFollowResponse + ), # Union types cannot be passed in as arguments in the type system + stream=True, + stream_cls=AsyncStream[DeploymentFollowResponse], + ) + + +class DeploymentsResourceWithRawResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_raw_response_wrapper( + deployments.create, + ) + self.retrieve = to_raw_response_wrapper( + deployments.retrieve, + ) + self.follow = to_raw_response_wrapper( + deployments.follow, + ) + + +class AsyncDeploymentsResourceWithRawResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_raw_response_wrapper( + deployments.create, + ) + self.retrieve = async_to_raw_response_wrapper( + deployments.retrieve, + ) + self.follow = async_to_raw_response_wrapper( + deployments.follow, + ) + + +class DeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_streamed_response_wrapper( + deployments.create, + ) + self.retrieve = to_streamed_response_wrapper( + deployments.retrieve, + ) + self.follow = to_streamed_response_wrapper( + deployments.follow, + ) + + +class AsyncDeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_streamed_response_wrapper( + deployments.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + deployments.retrieve, + ) + self.follow = async_to_streamed_response_wrapper( + deployments.follow, + ) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index d6ca955..93a1ee8 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -9,5 +9,9 @@ from .browser_delete_params import BrowserDeleteParams as BrowserDeleteParams from .browser_list_response import BrowserListResponse as BrowserListResponse from .browser_create_response import BrowserCreateResponse as BrowserCreateResponse +from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams from .browser_persistence_param import BrowserPersistenceParam as BrowserPersistenceParam from .browser_retrieve_response import BrowserRetrieveResponse as BrowserRetrieveResponse +from .deployment_create_response import DeploymentCreateResponse as DeploymentCreateResponse +from .deployment_follow_response import DeploymentFollowResponse as DeploymentFollowResponse +from .deployment_retrieve_response import DeploymentRetrieveResponse as DeploymentRetrieveResponse diff --git a/src/kernel/types/deployment_create_params.py b/src/kernel/types/deployment_create_params.py new file mode 100644 index 0000000..6701c0a --- /dev/null +++ b/src/kernel/types/deployment_create_params.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict +from typing_extensions import Literal, Required, TypedDict + +from .._types import FileTypes + +__all__ = ["DeploymentCreateParams"] + + +class DeploymentCreateParams(TypedDict, total=False): + entrypoint_rel_path: Required[str] + """Relative path to the entrypoint of the application""" + + file: Required[FileTypes] + """ZIP file containing the application source directory""" + + env_vars: Dict[str, str] + """Map of environment variables to set for the deployed application. + + Each key-value pair represents an environment variable. + """ + + force: bool + """Allow overwriting an existing app version""" + + region: Literal["aws.us-east-1a"] + """Region for deployment. Currently we only support "aws.us-east-1a" """ + + version: str + """Version of the application. Can be any string.""" diff --git a/src/kernel/types/deployment_create_response.py b/src/kernel/types/deployment_create_response.py new file mode 100644 index 0000000..0f5d2b2 --- /dev/null +++ b/src/kernel/types/deployment_create_response.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentCreateResponse"] + + +class DeploymentCreateResponse(BaseModel): + id: str + """Unique identifier for the deployment""" + + created_at: datetime + """Timestamp when the deployment was created""" + + region: str + """Deployment region code""" + + status: Literal["queued", "in_progress", "running", "failed", "stopped"] + """Current status of the deployment""" + + entrypoint_rel_path: Optional[str] = None + """Relative path to the application entrypoint""" + + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this deployment""" + + status_reason: Optional[str] = None + """Status reason""" + + updated_at: Optional[datetime] = None + """Timestamp when the deployment was last updated""" diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py new file mode 100644 index 0000000..09f1abc --- /dev/null +++ b/src/kernel/types/deployment_follow_response.py @@ -0,0 +1,129 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel + +__all__ = [ + "DeploymentFollowResponse", + "LogEvent", + "DeploymentStateEvent", + "DeploymentStateEventDeployment", + "AppVersionSummaryEvent", + "ErrorEvent", + "ErrorEventError", + "ErrorEventErrorDetail", + "ErrorEventErrorInnerError", +] + + +class LogEvent(BaseModel): + event: Literal["log"] + """Event type identifier (always "log").""" + + message: str + """Log message text.""" + + timestamp: Optional[datetime] = None + """Time the log entry was produced.""" + + +class DeploymentStateEventDeployment(BaseModel): + id: str + """Unique identifier for the deployment""" + + created_at: datetime + """Timestamp when the deployment was created""" + + region: str + """Deployment region code""" + + status: Literal["queued", "in_progress", "running", "failed", "stopped"] + """Current status of the deployment""" + + entrypoint_rel_path: Optional[str] = None + """Relative path to the application entrypoint""" + + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this deployment""" + + status_reason: Optional[str] = None + """Status reason""" + + updated_at: Optional[datetime] = None + """Timestamp when the deployment was last updated""" + + +class DeploymentStateEvent(BaseModel): + deployment: DeploymentStateEventDeployment + """Deployment record information.""" + + event: Literal["deployment_state"] + """Event type identifier (always "deployment_state").""" + + timestamp: Optional[datetime] = None + """Time the state was reported.""" + + +class AppVersionSummaryEvent(BaseModel): + id: Optional[str] = None + """Unique identifier for the app version""" + + app_name: Optional[str] = None + """Name of the application""" + + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this app version""" + + event: Optional[Literal["app_version_summary"]] = None + """Event type identifier (always "app_version_summary").""" + + region: Optional[str] = None + """Deployment region code""" + + version: Optional[str] = None + """Version label for the application""" + + +class ErrorEventErrorDetail(BaseModel): + code: Optional[str] = None + """Lower-level error code providing more specific detail""" + + message: Optional[str] = None + """Further detail about the error""" + + +class ErrorEventErrorInnerError(BaseModel): + code: Optional[str] = None + """Lower-level error code providing more specific detail""" + + message: Optional[str] = None + """Further detail about the error""" + + +class ErrorEventError(BaseModel): + code: str + """Application-specific error code (machine-readable)""" + + message: str + """Human-readable error description for debugging""" + + details: Optional[List[ErrorEventErrorDetail]] = None + """Additional error details (for multiple errors)""" + + inner_error: Optional[ErrorEventErrorInnerError] = None + + +class ErrorEvent(BaseModel): + error: Optional[ErrorEventError] = None + + event: Optional[Literal["error"]] = None + """Event type identifier (always "error").""" + + +DeploymentFollowResponse: TypeAlias = Annotated[ + Union[LogEvent, DeploymentStateEvent, AppVersionSummaryEvent, ErrorEvent], PropertyInfo(discriminator="event") +] diff --git a/src/kernel/types/deployment_retrieve_response.py b/src/kernel/types/deployment_retrieve_response.py new file mode 100644 index 0000000..efe9f7b --- /dev/null +++ b/src/kernel/types/deployment_retrieve_response.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentRetrieveResponse"] + + +class DeploymentRetrieveResponse(BaseModel): + id: str + """Unique identifier for the deployment""" + + created_at: datetime + """Timestamp when the deployment was created""" + + region: str + """Deployment region code""" + + status: Literal["queued", "in_progress", "running", "failed", "stopped"] + """Current status of the deployment""" + + entrypoint_rel_path: Optional[str] = None + """Relative path to the application entrypoint""" + + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this deployment""" + + status_reason: Optional[str] = None + """Status reason""" + + updated_at: Optional[datetime] = None + """Timestamp when the deployment was last updated""" diff --git a/tests/api_resources/test_deployments.py b/tests/api_resources/test_deployments.py new file mode 100644 index 0000000..4bd80fc --- /dev/null +++ b/tests/api_resources/test_deployments.py @@ -0,0 +1,304 @@ +# 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 kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types import DeploymentCreateResponse, 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"]) + + @pytest.mark.skip() + @parametrize + def test_method_create(self, client: Kernel) -> None: + deployment = client.deployments.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_method_create_with_all_params(self, client: Kernel) -> None: + deployment = client.deployments.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + env_vars={"foo": "string"}, + force=False, + region="aws.us-east-1a", + version="1.0.0", + ) + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_create(self, client: Kernel) -> None: + response = client.deployments.with_raw_response.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = response.parse() + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_create(self, client: Kernel) -> None: + with client.deployments.with_streaming_response.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = response.parse() + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + deployment = client.deployments.retrieve( + "id", + ) + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.deployments.with_raw_response.retrieve( + "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"]) + + @pytest.mark.skip() + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.deployments.with_streaming_response.retrieve( + "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 + + @pytest.mark.skip() + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.deployments.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_method_follow(self, client: Kernel) -> None: + deployment_stream = client.deployments.follow( + "id", + ) + deployment_stream.response.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_raw_response_follow(self, client: Kernel) -> None: + response = client.deployments.with_raw_response.follow( + "id", + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_streaming_response_follow(self, client: Kernel) -> None: + with client.deployments.with_streaming_response.follow( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_path_params_follow(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.deployments.with_raw_response.follow( + "", + ) + + +class TestAsyncDeployments: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create(self, async_client: AsyncKernel) -> None: + deployment = await async_client.deployments.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: + deployment = await async_client.deployments.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + env_vars={"foo": "string"}, + force=False, + region="aws.us-east-1a", + version="1.0.0", + ) + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_create(self, async_client: AsyncKernel) -> None: + response = await async_client.deployments.with_raw_response.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deployment = await response.parse() + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: + async with async_client.deployments.with_streaming_response.create( + entrypoint_rel_path="src/app.py", + file=b"raw file contents", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deployment = await response.parse() + assert_matches_type(DeploymentCreateResponse, deployment, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip() + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + deployment = await async_client.deployments.retrieve( + "id", + ) + assert_matches_type(DeploymentRetrieveResponse, deployment, path=["response"]) + + @pytest.mark.skip() + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.deployments.with_raw_response.retrieve( + "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"]) + + @pytest.mark.skip() + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.deployments.with_streaming_response.retrieve( + "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 + + @pytest.mark.skip() + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.deployments.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_method_follow(self, async_client: AsyncKernel) -> None: + deployment_stream = await async_client.deployments.follow( + "id", + ) + await deployment_stream.response.aclose() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_raw_response_follow(self, async_client: AsyncKernel) -> None: + response = await async_client.deployments.with_raw_response.follow( + "id", + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + await stream.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_streaming_response_follow(self, async_client: AsyncKernel) -> None: + async with async_client.deployments.with_streaming_response.follow( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_path_params_follow(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.deployments.with_raw_response.follow( + "", + ) From 452e83c41d808b97e1ff54cdfa79d74abccfc9b5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 20:04:00 +0000 Subject: [PATCH 06/23] feat(api): update via SDK Studio --- .stats.yml | 4 +-- .../types/apps/deployment_follow_response.py | 2 +- .../types/deployment_follow_response.py | 30 +++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index f34bfc3..f219d4b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-d2dfee8d576aa73f6075e6da61228571cb2e844b969a06067e34e43eb7898554.yml -openapi_spec_hash: 9981744bf9c27426cdf721f7b27cf093 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aec3b879aa30638614c6217afbafcf737f37ac78ef3a51186dbf7b6fbf9e91ef.yml +openapi_spec_hash: 0aba27c707612e35b4068b1d748dc379 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/apps/deployment_follow_response.py b/src/kernel/types/apps/deployment_follow_response.py index eb1ded7..cee006c 100644 --- a/src/kernel/types/apps/deployment_follow_response.py +++ b/src/kernel/types/apps/deployment_follow_response.py @@ -41,7 +41,7 @@ class LogEvent(BaseModel): message: str """Log message text.""" - timestamp: Optional[datetime] = None + timestamp: datetime """Time the log entry was produced.""" diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 09f1abc..59830fa 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -27,7 +27,7 @@ class LogEvent(BaseModel): message: str """Log message text.""" - timestamp: Optional[datetime] = None + timestamp: datetime """Time the log entry was produced.""" @@ -64,29 +64,32 @@ class DeploymentStateEvent(BaseModel): event: Literal["deployment_state"] """Event type identifier (always "deployment_state").""" - timestamp: Optional[datetime] = None + timestamp: datetime """Time the state was reported.""" class AppVersionSummaryEvent(BaseModel): - id: Optional[str] = None + id: str """Unique identifier for the app version""" - app_name: Optional[str] = None + app_name: str """Name of the application""" - env_vars: Optional[Dict[str, str]] = None - """Environment variables configured for this app version""" - - event: Optional[Literal["app_version_summary"]] = None + event: Literal["app_version_summary"] """Event type identifier (always "app_version_summary").""" - region: Optional[str] = None + region: str """Deployment region code""" - version: Optional[str] = None + timestamp: datetime + """Time the state was reported.""" + + version: str """Version label for the application""" + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this app version""" + class ErrorEventErrorDetail(BaseModel): code: Optional[str] = None @@ -118,11 +121,14 @@ class ErrorEventError(BaseModel): class ErrorEvent(BaseModel): - error: Optional[ErrorEventError] = None + error: ErrorEventError - event: Optional[Literal["error"]] = None + event: Literal["error"] """Event type identifier (always "error").""" + timestamp: datetime + """Time the error occurred.""" + DeploymentFollowResponse: TypeAlias = Annotated[ Union[LogEvent, DeploymentStateEvent, AppVersionSummaryEvent, ErrorEvent], PropertyInfo(discriminator="event") From d51332b18af547affb215d9a7596bbbdb7ccff24 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 21:04:27 +0000 Subject: [PATCH 07/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/deployment_follow_response.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f219d4b..c68e415 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aec3b879aa30638614c6217afbafcf737f37ac78ef3a51186dbf7b6fbf9e91ef.yml -openapi_spec_hash: 0aba27c707612e35b4068b1d748dc379 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aac74422364f9d25e30fcefd510297580b77be4b84c71416c5b9de5b882e5945.yml +openapi_spec_hash: 4d42a5d93bd82754acf11e32e7438a04 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 59830fa..60860c1 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -87,6 +87,9 @@ class AppVersionSummaryEvent(BaseModel): version: str """Version label for the application""" + actions: Optional[List[str]] = None + """List of actions available on the app""" + env_vars: Optional[Dict[str, str]] = None """Environment variables configured for this app version""" From 76991114e757c0c054e89d614619e38b2ec7d918 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 22:37:33 +0000 Subject: [PATCH 08/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/app_list_response.py | 4 ++-- src/kernel/types/deployment_create_response.py | 2 +- src/kernel/types/deployment_follow_response.py | 4 ++-- src/kernel/types/deployment_retrieve_response.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index c68e415..3f66d22 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-aac74422364f9d25e30fcefd510297580b77be4b84c71416c5b9de5b882e5945.yml -openapi_spec_hash: 4d42a5d93bd82754acf11e32e7438a04 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2fed6c2aef6fb20a2815d0ed36d801c566a73ea11a66db5d892b1533a1fac19e.yml +openapi_spec_hash: 55559a2ca985ed36cb8a13b09f80dcb5 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/app_list_response.py b/src/kernel/types/app_list_response.py index 8a6f621..1d35fd2 100644 --- a/src/kernel/types/app_list_response.py +++ b/src/kernel/types/app_list_response.py @@ -1,7 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Dict, List, Optional -from typing_extensions import TypeAlias +from typing_extensions import Literal, TypeAlias from .._models import BaseModel @@ -15,7 +15,7 @@ class AppListResponseItem(BaseModel): app_name: str """Name of the application""" - region: str + region: Literal["aws.us-east-1a"] """Deployment region code""" version: str diff --git a/src/kernel/types/deployment_create_response.py b/src/kernel/types/deployment_create_response.py index 0f5d2b2..c14bf27 100644 --- a/src/kernel/types/deployment_create_response.py +++ b/src/kernel/types/deployment_create_response.py @@ -16,7 +16,7 @@ class DeploymentCreateResponse(BaseModel): created_at: datetime """Timestamp when the deployment was created""" - region: str + region: Literal["aws.us-east-1a"] """Deployment region code""" status: Literal["queued", "in_progress", "running", "failed", "stopped"] diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 60860c1..bcc98a0 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -38,7 +38,7 @@ class DeploymentStateEventDeployment(BaseModel): created_at: datetime """Timestamp when the deployment was created""" - region: str + region: Literal["aws.us-east-1a"] """Deployment region code""" status: Literal["queued", "in_progress", "running", "failed", "stopped"] @@ -78,7 +78,7 @@ class AppVersionSummaryEvent(BaseModel): event: Literal["app_version_summary"] """Event type identifier (always "app_version_summary").""" - region: str + region: Literal["aws.us-east-1a"] """Deployment region code""" timestamp: datetime diff --git a/src/kernel/types/deployment_retrieve_response.py b/src/kernel/types/deployment_retrieve_response.py index efe9f7b..28c0d4b 100644 --- a/src/kernel/types/deployment_retrieve_response.py +++ b/src/kernel/types/deployment_retrieve_response.py @@ -16,7 +16,7 @@ class DeploymentRetrieveResponse(BaseModel): created_at: datetime """Timestamp when the deployment was created""" - region: str + region: Literal["aws.us-east-1a"] """Deployment region code""" status: Literal["queued", "in_progress", "running", "failed", "stopped"] From eed8e6769fd4982cadb277aa4c271c211992077a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:01:10 +0000 Subject: [PATCH 09/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/deployment_follow_response.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3f66d22..4dea91f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2fed6c2aef6fb20a2815d0ed36d801c566a73ea11a66db5d892b1533a1fac19e.yml -openapi_spec_hash: 55559a2ca985ed36cb8a13b09f80dcb5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-da3b6999bce525461011a620a559d34d4b4ab1d073758e7add4d2ba09f57a2ba.yml +openapi_spec_hash: 7bec5f31fa27666a3955076653c6ac40 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index bcc98a0..757b51a 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -72,6 +72,9 @@ class AppVersionSummaryEvent(BaseModel): id: str """Unique identifier for the app version""" + actions: List[str] + """List of actions available on the app""" + app_name: str """Name of the application""" @@ -87,9 +90,6 @@ class AppVersionSummaryEvent(BaseModel): version: str """Version label for the application""" - actions: Optional[List[str]] = None - """List of actions available on the app""" - env_vars: Optional[Dict[str, str]] = None """Environment variables configured for this app version""" From c1cdbcc6e555ab5fc7ecc229095ff7d0bf272e1a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:12:42 +0000 Subject: [PATCH 10/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/deployment_follow_response.py | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4dea91f..3ea11ab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-da3b6999bce525461011a620a559d34d4b4ab1d073758e7add4d2ba09f57a2ba.yml -openapi_spec_hash: 7bec5f31fa27666a3955076653c6ac40 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b8c3224543bfd828075063a87302ec205b54f8b24658cc869b98aa81d995d855.yml +openapi_spec_hash: 52f5b821303fef54e61bae285f185200 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 757b51a..44a17a6 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -13,6 +13,7 @@ "DeploymentStateEvent", "DeploymentStateEventDeployment", "AppVersionSummaryEvent", + "AppVersionSummaryEventAction", "ErrorEvent", "ErrorEventError", "ErrorEventErrorDetail", @@ -68,11 +69,16 @@ class DeploymentStateEvent(BaseModel): """Time the state was reported.""" +class AppVersionSummaryEventAction(BaseModel): + name: str + """Name of the action""" + + class AppVersionSummaryEvent(BaseModel): id: str """Unique identifier for the app version""" - actions: List[str] + actions: List[AppVersionSummaryEventAction] """List of actions available on the app""" app_name: str From 8073db60205835e3abb6c494e24bb034283c55f2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:13:55 +0000 Subject: [PATCH 11/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/deployment_follow_response.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3ea11ab..3493617 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b8c3224543bfd828075063a87302ec205b54f8b24658cc869b98aa81d995d855.yml -openapi_spec_hash: 52f5b821303fef54e61bae285f185200 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ba02d679c34c3af5ea47ec2b1a7387785d831e09f35bebfef9f05538ff380c3b.yml +openapi_spec_hash: 7ddbbe7354f65437d4eb567e8b042552 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 44a17a6..58203f8 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -70,7 +70,7 @@ class DeploymentStateEvent(BaseModel): class AppVersionSummaryEventAction(BaseModel): - name: str + name: Optional[str] = None """Name of the action""" From fe8d70b1f0a0725c37c794aeb5a7a466bc13cdf3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:14:42 +0000 Subject: [PATCH 12/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/deployment_follow_response.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3493617..bb23445 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-ba02d679c34c3af5ea47ec2b1a7387785d831e09f35bebfef9f05538ff380c3b.yml -openapi_spec_hash: 7ddbbe7354f65437d4eb567e8b042552 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-f7fa782f119b02d610bac1dbc75bf8355e73169d978997527f643e24036dabdd.yml +openapi_spec_hash: 9543dfe156b1c42a2fe4d3767e6b0778 config_hash: a085d1b39ddf0b26ee798501a9f47e20 diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 58203f8..44a17a6 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -70,7 +70,7 @@ class DeploymentStateEvent(BaseModel): class AppVersionSummaryEventAction(BaseModel): - name: Optional[str] = None + name: str """Name of the action""" From 235bf248a71505c9d5d536f1b6a7120e43b9cedc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 02:39:24 +0000 Subject: [PATCH 13/23] chore(tests): add tests for httpx client instantiation & proxies --- tests/test_client.py | 53 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/test_client.py b/tests/test_client.py index 3a6dcfb..9f38a30 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -27,7 +27,14 @@ from kernel._models import BaseModel, FinalRequestOptions from kernel._constants import RAW_RESPONSE_HEADER from kernel._exceptions import KernelError, APIStatusError, APITimeoutError, APIResponseValidationError -from kernel._base_client import DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, make_request_options +from kernel._base_client import ( + DEFAULT_TIMEOUT, + HTTPX_DEFAULT_TIMEOUT, + BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, + make_request_options, +) from kernel.types.browser_create_params import BrowserCreateParams from .utils import update_env @@ -837,6 +844,28 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" + def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects @@ -1716,6 +1745,28 @@ async def test_main() -> None: time.sleep(0.1) + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) async def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects From bcfcef2eb9cd584ad6ec508956d59b34211d2e14 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:09:23 +0000 Subject: [PATCH 14/23] chore(internal): update conftest.py --- tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 6d3cc20..3a11d3f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os From fb3fba16b9149449f8327b909210d42ee7744ba4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 06:39:59 +0000 Subject: [PATCH 15/23] chore(ci): enable for pull requests --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51b16df..c3f5bc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: From ff0793585ded6d9ea6c50947b9915f560221ed0f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:09:43 +0000 Subject: [PATCH 16/23] feat(api): update via SDK Studio --- .stats.yml | 8 +- api.md | 20 ++- src/kernel/_client.py | 10 +- src/kernel/resources/__init__.py | 14 ++ src/kernel/resources/apps/__init__.py | 14 -- src/kernel/resources/apps/apps.py | 32 ---- .../resources/{apps => }/invocations.py | 115 +++++++++++-- src/kernel/types/__init__.py | 9 ++ src/kernel/types/apps/__init__.py | 5 - .../types/apps/deployment_follow_response.py | 14 +- .../types/deployment_follow_response.py | 76 +-------- src/kernel/types/deployment_state_event.py | 46 ++++++ .../{apps => }/invocation_create_params.py | 2 +- .../{apps => }/invocation_create_response.py | 2 +- .../types/invocation_follow_response.py | 41 +++++ .../invocation_retrieve_response.py | 2 +- src/kernel/types/invocation_state_event.py | 57 +++++++ .../{apps => }/invocation_update_params.py | 0 .../{apps => }/invocation_update_response.py | 2 +- src/kernel/types/shared/__init__.py | 4 + src/kernel/types/shared/error_detail.py | 15 ++ src/kernel/types/shared/log_event.py | 19 +++ .../{apps => }/test_invocations.py | 152 ++++++++++++++---- 23 files changed, 474 insertions(+), 185 deletions(-) rename src/kernel/resources/{apps => }/invocations.py (75%) create mode 100644 src/kernel/types/deployment_state_event.py rename src/kernel/types/{apps => }/invocation_create_params.py (95%) rename src/kernel/types/{apps => }/invocation_create_response.py (95%) create mode 100644 src/kernel/types/invocation_follow_response.py rename src/kernel/types/{apps => }/invocation_retrieve_response.py (97%) create mode 100644 src/kernel/types/invocation_state_event.py rename src/kernel/types/{apps => }/invocation_update_params.py (100%) rename src/kernel/types/{apps => }/invocation_update_response.py (97%) create mode 100644 src/kernel/types/shared/__init__.py create mode 100644 src/kernel/types/shared/error_detail.py create mode 100644 src/kernel/types/shared/log_event.py rename tests/api_resources/{apps => }/test_invocations.py (65%) diff --git a/.stats.yml b/.stats.yml index bb23445..b912099 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 14 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-f7fa782f119b02d610bac1dbc75bf8355e73169d978997527f643e24036dabdd.yml -openapi_spec_hash: 9543dfe156b1c42a2fe4d3767e6b0778 -config_hash: a085d1b39ddf0b26ee798501a9f47e20 +configured_endpoints: 15 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5d4e11bc46eeecee7363d56a9dfe946acee997d5b352c2b0a50c20e742c54d2d.yml +openapi_spec_hash: 333e53ad9c706296b9afdb8ff73bec8f +config_hash: 4e2f9aebc2153d5caf7bb8b2eb107026 diff --git a/api.md b/api.md index db76da3..9a7d9a7 100644 --- a/api.md +++ b/api.md @@ -1,9 +1,16 @@ +# Shared Types + +```python +from kernel.types import ErrorDetail, LogEvent +``` + # Deployments Types: ```python from kernel.types import ( + DeploymentStateEvent, DeploymentCreateResponse, DeploymentRetrieveResponse, DeploymentFollowResponse, @@ -41,23 +48,26 @@ Methods: - client.apps.deployments.create(\*\*params) -> DeploymentCreateResponse - client.apps.deployments.follow(id) -> DeploymentFollowResponse -## Invocations +# Invocations Types: ```python -from kernel.types.apps import ( +from kernel.types import ( + InvocationStateEvent, InvocationCreateResponse, InvocationRetrieveResponse, InvocationUpdateResponse, + InvocationFollowResponse, ) ``` Methods: -- client.apps.invocations.create(\*\*params) -> InvocationCreateResponse -- client.apps.invocations.retrieve(id) -> InvocationRetrieveResponse -- client.apps.invocations.update(id, \*\*params) -> InvocationUpdateResponse +- client.invocations.create(\*\*params) -> InvocationCreateResponse +- client.invocations.retrieve(id) -> InvocationRetrieveResponse +- client.invocations.update(id, \*\*params) -> InvocationUpdateResponse +- client.invocations.follow(id) -> InvocationFollowResponse # Browsers diff --git a/src/kernel/_client.py b/src/kernel/_client.py index 084d2a5..63a7dc9 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -21,7 +21,7 @@ ) from ._utils import is_given, get_async_library from ._version import __version__ -from .resources import browsers, deployments +from .resources import browsers, deployments, invocations from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import KernelError, APIStatusError from ._base_client import ( @@ -52,6 +52,7 @@ class Kernel(SyncAPIClient): deployments: deployments.DeploymentsResource apps: apps.AppsResource + invocations: invocations.InvocationsResource browsers: browsers.BrowsersResource with_raw_response: KernelWithRawResponse with_streaming_response: KernelWithStreamedResponse @@ -136,6 +137,7 @@ def __init__( self.deployments = deployments.DeploymentsResource(self) self.apps = apps.AppsResource(self) + self.invocations = invocations.InvocationsResource(self) self.browsers = browsers.BrowsersResource(self) self.with_raw_response = KernelWithRawResponse(self) self.with_streaming_response = KernelWithStreamedResponse(self) @@ -250,6 +252,7 @@ def _make_status_error( class AsyncKernel(AsyncAPIClient): deployments: deployments.AsyncDeploymentsResource apps: apps.AsyncAppsResource + invocations: invocations.AsyncInvocationsResource browsers: browsers.AsyncBrowsersResource with_raw_response: AsyncKernelWithRawResponse with_streaming_response: AsyncKernelWithStreamedResponse @@ -334,6 +337,7 @@ def __init__( self.deployments = deployments.AsyncDeploymentsResource(self) self.apps = apps.AsyncAppsResource(self) + self.invocations = invocations.AsyncInvocationsResource(self) self.browsers = browsers.AsyncBrowsersResource(self) self.with_raw_response = AsyncKernelWithRawResponse(self) self.with_streaming_response = AsyncKernelWithStreamedResponse(self) @@ -449,6 +453,7 @@ class KernelWithRawResponse: def __init__(self, client: Kernel) -> None: self.deployments = deployments.DeploymentsResourceWithRawResponse(client.deployments) self.apps = apps.AppsResourceWithRawResponse(client.apps) + self.invocations = invocations.InvocationsResourceWithRawResponse(client.invocations) self.browsers = browsers.BrowsersResourceWithRawResponse(client.browsers) @@ -456,6 +461,7 @@ class AsyncKernelWithRawResponse: def __init__(self, client: AsyncKernel) -> None: self.deployments = deployments.AsyncDeploymentsResourceWithRawResponse(client.deployments) self.apps = apps.AsyncAppsResourceWithRawResponse(client.apps) + self.invocations = invocations.AsyncInvocationsResourceWithRawResponse(client.invocations) self.browsers = browsers.AsyncBrowsersResourceWithRawResponse(client.browsers) @@ -463,6 +469,7 @@ class KernelWithStreamedResponse: def __init__(self, client: Kernel) -> None: self.deployments = deployments.DeploymentsResourceWithStreamingResponse(client.deployments) self.apps = apps.AppsResourceWithStreamingResponse(client.apps) + self.invocations = invocations.InvocationsResourceWithStreamingResponse(client.invocations) self.browsers = browsers.BrowsersResourceWithStreamingResponse(client.browsers) @@ -470,6 +477,7 @@ class AsyncKernelWithStreamedResponse: def __init__(self, client: AsyncKernel) -> None: self.deployments = deployments.AsyncDeploymentsResourceWithStreamingResponse(client.deployments) self.apps = apps.AsyncAppsResourceWithStreamingResponse(client.apps) + self.invocations = invocations.AsyncInvocationsResourceWithStreamingResponse(client.invocations) self.browsers = browsers.AsyncBrowsersResourceWithStreamingResponse(client.browsers) diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index f65d1db..3b6a4d6 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -24,6 +24,14 @@ DeploymentsResourceWithStreamingResponse, AsyncDeploymentsResourceWithStreamingResponse, ) +from .invocations import ( + InvocationsResource, + AsyncInvocationsResource, + InvocationsResourceWithRawResponse, + AsyncInvocationsResourceWithRawResponse, + InvocationsResourceWithStreamingResponse, + AsyncInvocationsResourceWithStreamingResponse, +) __all__ = [ "DeploymentsResource", @@ -38,6 +46,12 @@ "AsyncAppsResourceWithRawResponse", "AppsResourceWithStreamingResponse", "AsyncAppsResourceWithStreamingResponse", + "InvocationsResource", + "AsyncInvocationsResource", + "InvocationsResourceWithRawResponse", + "AsyncInvocationsResourceWithRawResponse", + "InvocationsResourceWithStreamingResponse", + "AsyncInvocationsResourceWithStreamingResponse", "BrowsersResource", "AsyncBrowsersResource", "BrowsersResourceWithRawResponse", diff --git a/src/kernel/resources/apps/__init__.py b/src/kernel/resources/apps/__init__.py index 5602ad7..6ce731d 100644 --- a/src/kernel/resources/apps/__init__.py +++ b/src/kernel/resources/apps/__init__.py @@ -16,14 +16,6 @@ DeploymentsResourceWithStreamingResponse, AsyncDeploymentsResourceWithStreamingResponse, ) -from .invocations import ( - InvocationsResource, - AsyncInvocationsResource, - InvocationsResourceWithRawResponse, - AsyncInvocationsResourceWithRawResponse, - InvocationsResourceWithStreamingResponse, - AsyncInvocationsResourceWithStreamingResponse, -) __all__ = [ "DeploymentsResource", @@ -32,12 +24,6 @@ "AsyncDeploymentsResourceWithRawResponse", "DeploymentsResourceWithStreamingResponse", "AsyncDeploymentsResourceWithStreamingResponse", - "InvocationsResource", - "AsyncInvocationsResource", - "InvocationsResourceWithRawResponse", - "AsyncInvocationsResourceWithRawResponse", - "InvocationsResourceWithStreamingResponse", - "AsyncInvocationsResourceWithStreamingResponse", "AppsResource", "AsyncAppsResource", "AppsResourceWithRawResponse", diff --git a/src/kernel/resources/apps/apps.py b/src/kernel/resources/apps/apps.py index 3769bd5..726db20 100644 --- a/src/kernel/resources/apps/apps.py +++ b/src/kernel/resources/apps/apps.py @@ -23,14 +23,6 @@ DeploymentsResourceWithStreamingResponse, AsyncDeploymentsResourceWithStreamingResponse, ) -from .invocations import ( - InvocationsResource, - AsyncInvocationsResource, - InvocationsResourceWithRawResponse, - AsyncInvocationsResourceWithRawResponse, - InvocationsResourceWithStreamingResponse, - AsyncInvocationsResourceWithStreamingResponse, -) from ..._base_client import make_request_options from ...types.app_list_response import AppListResponse @@ -42,10 +34,6 @@ class AppsResource(SyncAPIResource): def deployments(self) -> DeploymentsResource: return DeploymentsResource(self._client) - @cached_property - def invocations(self) -> InvocationsResource: - return InvocationsResource(self._client) - @cached_property def with_raw_response(self) -> AppsResourceWithRawResponse: """ @@ -118,10 +106,6 @@ class AsyncAppsResource(AsyncAPIResource): def deployments(self) -> AsyncDeploymentsResource: return AsyncDeploymentsResource(self._client) - @cached_property - def invocations(self) -> AsyncInvocationsResource: - return AsyncInvocationsResource(self._client) - @cached_property def with_raw_response(self) -> AsyncAppsResourceWithRawResponse: """ @@ -201,10 +185,6 @@ def __init__(self, apps: AppsResource) -> None: def deployments(self) -> DeploymentsResourceWithRawResponse: return DeploymentsResourceWithRawResponse(self._apps.deployments) - @cached_property - def invocations(self) -> InvocationsResourceWithRawResponse: - return InvocationsResourceWithRawResponse(self._apps.invocations) - class AsyncAppsResourceWithRawResponse: def __init__(self, apps: AsyncAppsResource) -> None: @@ -218,10 +198,6 @@ def __init__(self, apps: AsyncAppsResource) -> None: def deployments(self) -> AsyncDeploymentsResourceWithRawResponse: return AsyncDeploymentsResourceWithRawResponse(self._apps.deployments) - @cached_property - def invocations(self) -> AsyncInvocationsResourceWithRawResponse: - return AsyncInvocationsResourceWithRawResponse(self._apps.invocations) - class AppsResourceWithStreamingResponse: def __init__(self, apps: AppsResource) -> None: @@ -235,10 +211,6 @@ def __init__(self, apps: AppsResource) -> None: def deployments(self) -> DeploymentsResourceWithStreamingResponse: return DeploymentsResourceWithStreamingResponse(self._apps.deployments) - @cached_property - def invocations(self) -> InvocationsResourceWithStreamingResponse: - return InvocationsResourceWithStreamingResponse(self._apps.invocations) - class AsyncAppsResourceWithStreamingResponse: def __init__(self, apps: AsyncAppsResource) -> None: @@ -251,7 +223,3 @@ def __init__(self, apps: AsyncAppsResource) -> None: @cached_property def deployments(self) -> AsyncDeploymentsResourceWithStreamingResponse: return AsyncDeploymentsResourceWithStreamingResponse(self._apps.deployments) - - @cached_property - def invocations(self) -> AsyncInvocationsResourceWithStreamingResponse: - return AsyncInvocationsResourceWithStreamingResponse(self._apps.invocations) diff --git a/src/kernel/resources/apps/invocations.py b/src/kernel/resources/invocations.py similarity index 75% rename from src/kernel/resources/apps/invocations.py rename to src/kernel/resources/invocations.py index b5413d4..c87b8d7 100644 --- a/src/kernel/resources/apps/invocations.py +++ b/src/kernel/resources/invocations.py @@ -2,25 +2,28 @@ from __future__ import annotations +from typing import Any, cast from typing_extensions import Literal 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 ( +from ..types import invocation_create_params, invocation_update_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 ...types.apps import invocation_create_params, invocation_update_params -from ..._base_client import make_request_options -from ...types.apps.invocation_create_response import InvocationCreateResponse -from ...types.apps.invocation_update_response import InvocationUpdateResponse -from ...types.apps.invocation_retrieve_response import InvocationRetrieveResponse +from .._streaming import Stream, AsyncStream +from .._base_client import make_request_options +from ..types.invocation_create_response import InvocationCreateResponse +from ..types.invocation_follow_response import InvocationFollowResponse +from ..types.invocation_update_response import InvocationUpdateResponse +from ..types.invocation_retrieve_response import InvocationRetrieveResponse __all__ = ["InvocationsResource", "AsyncInvocationsResource"] @@ -180,6 +183,46 @@ def update( cast_to=InvocationUpdateResponse, ) + def follow( + 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, + ) -> Stream[InvocationFollowResponse]: + """ + Establishes a Server-Sent Events (SSE) stream that delivers real-time logs and + status updates for an invocation. The stream terminates automatically once the + invocation reaches a terminal state. + + 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}") + extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} + return self._get( + f"/invocations/{id}/events", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, InvocationFollowResponse + ), # Union types cannot be passed in as arguments in the type system + stream=True, + stream_cls=Stream[InvocationFollowResponse], + ) + class AsyncInvocationsResource(AsyncAPIResource): @cached_property @@ -336,6 +379,46 @@ async def update( cast_to=InvocationUpdateResponse, ) + async def follow( + 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, + ) -> AsyncStream[InvocationFollowResponse]: + """ + Establishes a Server-Sent Events (SSE) stream that delivers real-time logs and + status updates for an invocation. The stream terminates automatically once the + invocation reaches a terminal state. + + 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}") + extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} + return await self._get( + f"/invocations/{id}/events", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast( + Any, InvocationFollowResponse + ), # Union types cannot be passed in as arguments in the type system + stream=True, + stream_cls=AsyncStream[InvocationFollowResponse], + ) + class InvocationsResourceWithRawResponse: def __init__(self, invocations: InvocationsResource) -> None: @@ -350,6 +433,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.update = to_raw_response_wrapper( invocations.update, ) + self.follow = to_raw_response_wrapper( + invocations.follow, + ) class AsyncInvocationsResourceWithRawResponse: @@ -365,6 +451,9 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.update = async_to_raw_response_wrapper( invocations.update, ) + self.follow = async_to_raw_response_wrapper( + invocations.follow, + ) class InvocationsResourceWithStreamingResponse: @@ -380,6 +469,9 @@ def __init__(self, invocations: InvocationsResource) -> None: self.update = to_streamed_response_wrapper( invocations.update, ) + self.follow = to_streamed_response_wrapper( + invocations.follow, + ) class AsyncInvocationsResourceWithStreamingResponse: @@ -395,3 +487,6 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None: self.update = async_to_streamed_response_wrapper( invocations.update, ) + self.follow = async_to_streamed_response_wrapper( + invocations.follow, + ) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 93a1ee8..4a5c229 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -2,16 +2,25 @@ from __future__ import annotations +from .shared import LogEvent as LogEvent, ErrorDetail as ErrorDetail from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_persistence import BrowserPersistence as BrowserPersistence from .browser_create_params import BrowserCreateParams as BrowserCreateParams from .browser_delete_params import BrowserDeleteParams as BrowserDeleteParams from .browser_list_response import BrowserListResponse as BrowserListResponse +from .deployment_state_event import DeploymentStateEvent as DeploymentStateEvent +from .invocation_state_event import InvocationStateEvent as InvocationStateEvent from .browser_create_response import BrowserCreateResponse as BrowserCreateResponse from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams +from .invocation_create_params import InvocationCreateParams as InvocationCreateParams +from .invocation_update_params import InvocationUpdateParams as InvocationUpdateParams from .browser_persistence_param import BrowserPersistenceParam as BrowserPersistenceParam from .browser_retrieve_response import BrowserRetrieveResponse as BrowserRetrieveResponse from .deployment_create_response import DeploymentCreateResponse as DeploymentCreateResponse from .deployment_follow_response import DeploymentFollowResponse as DeploymentFollowResponse +from .invocation_create_response import InvocationCreateResponse as InvocationCreateResponse +from .invocation_follow_response import InvocationFollowResponse as InvocationFollowResponse +from .invocation_update_response import InvocationUpdateResponse as InvocationUpdateResponse from .deployment_retrieve_response import DeploymentRetrieveResponse as DeploymentRetrieveResponse +from .invocation_retrieve_response import InvocationRetrieveResponse as InvocationRetrieveResponse diff --git a/src/kernel/types/apps/__init__.py b/src/kernel/types/apps/__init__.py index f4bf7a2..93aed9d 100644 --- a/src/kernel/types/apps/__init__.py +++ b/src/kernel/types/apps/__init__.py @@ -3,10 +3,5 @@ from __future__ import annotations from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams -from .invocation_create_params import InvocationCreateParams as InvocationCreateParams -from .invocation_update_params import InvocationUpdateParams as InvocationUpdateParams from .deployment_create_response import DeploymentCreateResponse as DeploymentCreateResponse from .deployment_follow_response import DeploymentFollowResponse as DeploymentFollowResponse -from .invocation_create_response import InvocationCreateResponse as InvocationCreateResponse -from .invocation_update_response import InvocationUpdateResponse as InvocationUpdateResponse -from .invocation_retrieve_response import InvocationRetrieveResponse as InvocationRetrieveResponse diff --git a/src/kernel/types/apps/deployment_follow_response.py b/src/kernel/types/apps/deployment_follow_response.py index cee006c..fae1b2b 100644 --- a/src/kernel/types/apps/deployment_follow_response.py +++ b/src/kernel/types/apps/deployment_follow_response.py @@ -6,8 +6,9 @@ from ..._utils import PropertyInfo from ..._models import BaseModel +from ..shared.log_event import LogEvent -__all__ = ["DeploymentFollowResponse", "StateEvent", "StateUpdateEvent", "LogEvent"] +__all__ = ["DeploymentFollowResponse", "StateEvent", "StateUpdateEvent"] class StateEvent(BaseModel): @@ -34,17 +35,6 @@ class StateUpdateEvent(BaseModel): """Time the state change occurred.""" -class LogEvent(BaseModel): - event: Literal["log"] - """Event type identifier (always "log").""" - - message: str - """Log message text.""" - - timestamp: datetime - """Time the log entry was produced.""" - - DeploymentFollowResponse: TypeAlias = Annotated[ Union[StateEvent, StateUpdateEvent, LogEvent], PropertyInfo(discriminator="event") ] diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 44a17a6..38afcad 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -6,69 +6,19 @@ from .._utils import PropertyInfo from .._models import BaseModel +from .shared.log_event import LogEvent +from .shared.error_detail import ErrorDetail +from .deployment_state_event import DeploymentStateEvent __all__ = [ "DeploymentFollowResponse", - "LogEvent", - "DeploymentStateEvent", - "DeploymentStateEventDeployment", "AppVersionSummaryEvent", "AppVersionSummaryEventAction", "ErrorEvent", "ErrorEventError", - "ErrorEventErrorDetail", - "ErrorEventErrorInnerError", ] -class LogEvent(BaseModel): - event: Literal["log"] - """Event type identifier (always "log").""" - - message: str - """Log message text.""" - - timestamp: datetime - """Time the log entry was produced.""" - - -class DeploymentStateEventDeployment(BaseModel): - id: str - """Unique identifier for the deployment""" - - created_at: datetime - """Timestamp when the deployment was created""" - - region: Literal["aws.us-east-1a"] - """Deployment region code""" - - status: Literal["queued", "in_progress", "running", "failed", "stopped"] - """Current status of the deployment""" - - entrypoint_rel_path: Optional[str] = None - """Relative path to the application entrypoint""" - - env_vars: Optional[Dict[str, str]] = None - """Environment variables configured for this deployment""" - - status_reason: Optional[str] = None - """Status reason""" - - updated_at: Optional[datetime] = None - """Timestamp when the deployment was last updated""" - - -class DeploymentStateEvent(BaseModel): - deployment: DeploymentStateEventDeployment - """Deployment record information.""" - - event: Literal["deployment_state"] - """Event type identifier (always "deployment_state").""" - - timestamp: datetime - """Time the state was reported.""" - - class AppVersionSummaryEventAction(BaseModel): name: str """Name of the action""" @@ -100,22 +50,6 @@ class AppVersionSummaryEvent(BaseModel): """Environment variables configured for this app version""" -class ErrorEventErrorDetail(BaseModel): - code: Optional[str] = None - """Lower-level error code providing more specific detail""" - - message: Optional[str] = None - """Further detail about the error""" - - -class ErrorEventErrorInnerError(BaseModel): - code: Optional[str] = None - """Lower-level error code providing more specific detail""" - - message: Optional[str] = None - """Further detail about the error""" - - class ErrorEventError(BaseModel): code: str """Application-specific error code (machine-readable)""" @@ -123,10 +57,10 @@ class ErrorEventError(BaseModel): message: str """Human-readable error description for debugging""" - details: Optional[List[ErrorEventErrorDetail]] = None + details: Optional[List[ErrorDetail]] = None """Additional error details (for multiple errors)""" - inner_error: Optional[ErrorEventErrorInnerError] = None + inner_error: Optional[ErrorDetail] = None class ErrorEvent(BaseModel): diff --git a/src/kernel/types/deployment_state_event.py b/src/kernel/types/deployment_state_event.py new file mode 100644 index 0000000..572d51b --- /dev/null +++ b/src/kernel/types/deployment_state_event.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["DeploymentStateEvent", "Deployment"] + + +class Deployment(BaseModel): + id: str + """Unique identifier for the deployment""" + + created_at: datetime + """Timestamp when the deployment was created""" + + region: Literal["aws.us-east-1a"] + """Deployment region code""" + + status: Literal["queued", "in_progress", "running", "failed", "stopped"] + """Current status of the deployment""" + + entrypoint_rel_path: Optional[str] = None + """Relative path to the application entrypoint""" + + env_vars: Optional[Dict[str, str]] = None + """Environment variables configured for this deployment""" + + status_reason: Optional[str] = None + """Status reason""" + + updated_at: Optional[datetime] = None + """Timestamp when the deployment was last updated""" + + +class DeploymentStateEvent(BaseModel): + deployment: Deployment + """Deployment record information.""" + + event: Literal["deployment_state"] + """Event type identifier (always "deployment_state").""" + + timestamp: datetime + """Time the state was reported.""" diff --git a/src/kernel/types/apps/invocation_create_params.py b/src/kernel/types/invocation_create_params.py similarity index 95% rename from src/kernel/types/apps/invocation_create_params.py rename to src/kernel/types/invocation_create_params.py index 01035ae..1d6bc64 100644 --- a/src/kernel/types/apps/invocation_create_params.py +++ b/src/kernel/types/invocation_create_params.py @@ -4,7 +4,7 @@ from typing_extensions import Required, Annotated, TypedDict -from ..._utils import PropertyInfo +from .._utils import PropertyInfo __all__ = ["InvocationCreateParams"] diff --git a/src/kernel/types/apps/invocation_create_response.py b/src/kernel/types/invocation_create_response.py similarity index 95% rename from src/kernel/types/apps/invocation_create_response.py rename to src/kernel/types/invocation_create_response.py index df4a166..d58f262 100644 --- a/src/kernel/types/apps/invocation_create_response.py +++ b/src/kernel/types/invocation_create_response.py @@ -3,7 +3,7 @@ from typing import Optional from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["InvocationCreateResponse"] diff --git a/src/kernel/types/invocation_follow_response.py b/src/kernel/types/invocation_follow_response.py new file mode 100644 index 0000000..b1693a1 --- /dev/null +++ b/src/kernel/types/invocation_follow_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypeAlias + +from .._utils import PropertyInfo +from .._models import BaseModel +from .shared.log_event import LogEvent +from .shared.error_detail import ErrorDetail +from .invocation_state_event import InvocationStateEvent + +__all__ = ["InvocationFollowResponse", "ErrorEvent", "ErrorEventError"] + + +class ErrorEventError(BaseModel): + code: str + """Application-specific error code (machine-readable)""" + + message: str + """Human-readable error description for debugging""" + + details: Optional[List[ErrorDetail]] = None + """Additional error details (for multiple errors)""" + + inner_error: Optional[ErrorDetail] = None + + +class ErrorEvent(BaseModel): + error: ErrorEventError + + event: Literal["error"] + """Event type identifier (always "error").""" + + timestamp: datetime + """Time the error occurred.""" + + +InvocationFollowResponse: TypeAlias = Annotated[ + Union[LogEvent, InvocationStateEvent, ErrorEvent], PropertyInfo(discriminator="event") +] diff --git a/src/kernel/types/apps/invocation_retrieve_response.py b/src/kernel/types/invocation_retrieve_response.py similarity index 97% rename from src/kernel/types/apps/invocation_retrieve_response.py rename to src/kernel/types/invocation_retrieve_response.py index f328b14..6626b53 100644 --- a/src/kernel/types/apps/invocation_retrieve_response.py +++ b/src/kernel/types/invocation_retrieve_response.py @@ -4,7 +4,7 @@ from datetime import datetime from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["InvocationRetrieveResponse"] diff --git a/src/kernel/types/invocation_state_event.py b/src/kernel/types/invocation_state_event.py new file mode 100644 index 0000000..6f30ea6 --- /dev/null +++ b/src/kernel/types/invocation_state_event.py @@ -0,0 +1,57 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["InvocationStateEvent", "Invocation"] + + +class Invocation(BaseModel): + id: str + """ID of the invocation""" + + action_name: str + """Name of the action invoked""" + + app_name: str + """Name of the application""" + + started_at: datetime + """RFC 3339 Nanoseconds timestamp when the invocation started""" + + status: Literal["queued", "running", "succeeded", "failed"] + """Status of the invocation""" + + finished_at: Optional[datetime] = None + """ + RFC 3339 Nanoseconds timestamp when the invocation finished (null if still + running) + """ + + output: Optional[str] = None + """Output produced by the action, rendered as a JSON string. + + This could be: string, number, boolean, array, object, or null. + """ + + payload: Optional[str] = None + """Payload provided to the invocation. + + This is a string that can be parsed as JSON. + """ + + status_reason: Optional[str] = None + """Status reason""" + + +class InvocationStateEvent(BaseModel): + event: Literal["invocation_state"] + """Event type identifier (always "invocation_state").""" + + invocation: Invocation + + timestamp: datetime + """Time the state was reported.""" diff --git a/src/kernel/types/apps/invocation_update_params.py b/src/kernel/types/invocation_update_params.py similarity index 100% rename from src/kernel/types/apps/invocation_update_params.py rename to src/kernel/types/invocation_update_params.py diff --git a/src/kernel/types/apps/invocation_update_response.py b/src/kernel/types/invocation_update_response.py similarity index 97% rename from src/kernel/types/apps/invocation_update_response.py rename to src/kernel/types/invocation_update_response.py index c30fc16..e0029a9 100644 --- a/src/kernel/types/apps/invocation_update_response.py +++ b/src/kernel/types/invocation_update_response.py @@ -4,7 +4,7 @@ from datetime import datetime from typing_extensions import Literal -from ..._models import BaseModel +from .._models import BaseModel __all__ = ["InvocationUpdateResponse"] diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py new file mode 100644 index 0000000..1f139b0 --- /dev/null +++ b/src/kernel/types/shared/__init__.py @@ -0,0 +1,4 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .log_event import LogEvent as LogEvent +from .error_detail import ErrorDetail as ErrorDetail diff --git a/src/kernel/types/shared/error_detail.py b/src/kernel/types/shared/error_detail.py new file mode 100644 index 0000000..24e655f --- /dev/null +++ b/src/kernel/types/shared/error_detail.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["ErrorDetail"] + + +class ErrorDetail(BaseModel): + code: Optional[str] = None + """Lower-level error code providing more specific detail""" + + message: Optional[str] = None + """Further detail about the error""" diff --git a/src/kernel/types/shared/log_event.py b/src/kernel/types/shared/log_event.py new file mode 100644 index 0000000..69dbc56 --- /dev/null +++ b/src/kernel/types/shared/log_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["LogEvent"] + + +class LogEvent(BaseModel): + event: Literal["log"] + """Event type identifier (always "log").""" + + message: str + """Log message text.""" + + timestamp: datetime + """Time the log entry was produced.""" diff --git a/tests/api_resources/apps/test_invocations.py b/tests/api_resources/test_invocations.py similarity index 65% rename from tests/api_resources/apps/test_invocations.py rename to tests/api_resources/test_invocations.py index 87dc31f..c11ea7c 100644 --- a/tests/api_resources/apps/test_invocations.py +++ b/tests/api_resources/test_invocations.py @@ -9,7 +9,7 @@ from kernel import Kernel, AsyncKernel from tests.utils import assert_matches_type -from kernel.types.apps import ( +from kernel.types import ( InvocationCreateResponse, InvocationUpdateResponse, InvocationRetrieveResponse, @@ -24,7 +24,7 @@ class TestInvocations: @pytest.mark.skip() @parametrize def test_method_create(self, client: Kernel) -> None: - invocation = client.apps.invocations.create( + invocation = client.invocations.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -34,7 +34,7 @@ def test_method_create(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_method_create_with_all_params(self, client: Kernel) -> None: - invocation = client.apps.invocations.create( + invocation = client.invocations.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -46,7 +46,7 @@ def test_method_create_with_all_params(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_raw_response_create(self, client: Kernel) -> None: - response = client.apps.invocations.with_raw_response.create( + response = client.invocations.with_raw_response.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -60,7 +60,7 @@ def test_raw_response_create(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_streaming_response_create(self, client: Kernel) -> None: - with client.apps.invocations.with_streaming_response.create( + with client.invocations.with_streaming_response.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -76,7 +76,7 @@ def test_streaming_response_create(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_method_retrieve(self, client: Kernel) -> None: - invocation = client.apps.invocations.retrieve( + invocation = client.invocations.retrieve( "id", ) assert_matches_type(InvocationRetrieveResponse, invocation, path=["response"]) @@ -84,7 +84,7 @@ def test_method_retrieve(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_raw_response_retrieve(self, client: Kernel) -> None: - response = client.apps.invocations.with_raw_response.retrieve( + response = client.invocations.with_raw_response.retrieve( "id", ) @@ -96,7 +96,7 @@ def test_raw_response_retrieve(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_streaming_response_retrieve(self, client: Kernel) -> None: - with client.apps.invocations.with_streaming_response.retrieve( + with client.invocations.with_streaming_response.retrieve( "id", ) as response: assert not response.is_closed @@ -111,14 +111,14 @@ def test_streaming_response_retrieve(self, client: Kernel) -> None: @parametrize def test_path_params_retrieve(self, client: Kernel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.apps.invocations.with_raw_response.retrieve( + client.invocations.with_raw_response.retrieve( "", ) @pytest.mark.skip() @parametrize def test_method_update(self, client: Kernel) -> None: - invocation = client.apps.invocations.update( + invocation = client.invocations.update( id="id", status="succeeded", ) @@ -127,7 +127,7 @@ def test_method_update(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_method_update_with_all_params(self, client: Kernel) -> None: - invocation = client.apps.invocations.update( + invocation = client.invocations.update( id="id", status="succeeded", output="output", @@ -137,7 +137,7 @@ def test_method_update_with_all_params(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_raw_response_update(self, client: Kernel) -> None: - response = client.apps.invocations.with_raw_response.update( + response = client.invocations.with_raw_response.update( id="id", status="succeeded", ) @@ -150,7 +150,7 @@ def test_raw_response_update(self, client: Kernel) -> None: @pytest.mark.skip() @parametrize def test_streaming_response_update(self, client: Kernel) -> None: - with client.apps.invocations.with_streaming_response.update( + with client.invocations.with_streaming_response.update( id="id", status="succeeded", ) as response: @@ -166,11 +166,60 @@ def test_streaming_response_update(self, client: Kernel) -> None: @parametrize def test_path_params_update(self, client: Kernel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.apps.invocations.with_raw_response.update( + client.invocations.with_raw_response.update( id="", status="succeeded", ) + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_method_follow(self, client: Kernel) -> None: + invocation_stream = client.invocations.follow( + "id", + ) + invocation_stream.response.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_raw_response_follow(self, client: Kernel) -> None: + response = client.invocations.with_raw_response.follow( + "id", + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = response.parse() + stream.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_streaming_response_follow(self, client: Kernel) -> None: + with client.invocations.with_streaming_response.follow( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = response.parse() + stream.close() + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + def test_path_params_follow(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.invocations.with_raw_response.follow( + "", + ) + class TestAsyncInvocations: parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) @@ -178,7 +227,7 @@ class TestAsyncInvocations: @pytest.mark.skip() @parametrize async def test_method_create(self, async_client: AsyncKernel) -> None: - invocation = await async_client.apps.invocations.create( + invocation = await async_client.invocations.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -188,7 +237,7 @@ async def test_method_create(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: - invocation = await async_client.apps.invocations.create( + invocation = await async_client.invocations.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -200,7 +249,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> @pytest.mark.skip() @parametrize async def test_raw_response_create(self, async_client: AsyncKernel) -> None: - response = await async_client.apps.invocations.with_raw_response.create( + response = await async_client.invocations.with_raw_response.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -214,7 +263,7 @@ async def test_raw_response_create(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: - async with async_client.apps.invocations.with_streaming_response.create( + async with async_client.invocations.with_streaming_response.create( action_name="analyze", app_name="my-app", version="1.0.0", @@ -230,7 +279,7 @@ async def test_streaming_response_create(self, async_client: AsyncKernel) -> Non @pytest.mark.skip() @parametrize async def test_method_retrieve(self, async_client: AsyncKernel) -> None: - invocation = await async_client.apps.invocations.retrieve( + invocation = await async_client.invocations.retrieve( "id", ) assert_matches_type(InvocationRetrieveResponse, invocation, path=["response"]) @@ -238,7 +287,7 @@ async def test_method_retrieve(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: - response = await async_client.apps.invocations.with_raw_response.retrieve( + response = await async_client.invocations.with_raw_response.retrieve( "id", ) @@ -250,7 +299,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: - async with async_client.apps.invocations.with_streaming_response.retrieve( + async with async_client.invocations.with_streaming_response.retrieve( "id", ) as response: assert not response.is_closed @@ -265,14 +314,14 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> N @parametrize async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.apps.invocations.with_raw_response.retrieve( + await async_client.invocations.with_raw_response.retrieve( "", ) @pytest.mark.skip() @parametrize async def test_method_update(self, async_client: AsyncKernel) -> None: - invocation = await async_client.apps.invocations.update( + invocation = await async_client.invocations.update( id="id", status="succeeded", ) @@ -281,7 +330,7 @@ async def test_method_update(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> None: - invocation = await async_client.apps.invocations.update( + invocation = await async_client.invocations.update( id="id", status="succeeded", output="output", @@ -291,7 +340,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> @pytest.mark.skip() @parametrize async def test_raw_response_update(self, async_client: AsyncKernel) -> None: - response = await async_client.apps.invocations.with_raw_response.update( + response = await async_client.invocations.with_raw_response.update( id="id", status="succeeded", ) @@ -304,7 +353,7 @@ async def test_raw_response_update(self, async_client: AsyncKernel) -> None: @pytest.mark.skip() @parametrize async def test_streaming_response_update(self, async_client: AsyncKernel) -> None: - async with async_client.apps.invocations.with_streaming_response.update( + async with async_client.invocations.with_streaming_response.update( id="id", status="succeeded", ) as response: @@ -320,7 +369,56 @@ async def test_streaming_response_update(self, async_client: AsyncKernel) -> Non @parametrize async def test_path_params_update(self, async_client: AsyncKernel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.apps.invocations.with_raw_response.update( + await async_client.invocations.with_raw_response.update( id="", status="succeeded", ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_method_follow(self, async_client: AsyncKernel) -> None: + invocation_stream = await async_client.invocations.follow( + "id", + ) + await invocation_stream.response.aclose() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_raw_response_follow(self, async_client: AsyncKernel) -> None: + response = await async_client.invocations.with_raw_response.follow( + "id", + ) + + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + stream = await response.parse() + await stream.close() + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_streaming_response_follow(self, async_client: AsyncKernel) -> None: + async with async_client.invocations.with_streaming_response.follow( + "id", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + stream = await response.parse() + await stream.close() + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints with content type text/event-stream, Prism mock server will fail" + ) + @parametrize + async def test_path_params_follow(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.invocations.with_raw_response.follow( + "", + ) From d26c519a798d8bf66baaef49af818b4108c3d92a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:20:37 +0000 Subject: [PATCH 17/23] feat(api): update via SDK Studio --- .stats.yml | 6 +-- api.md | 2 +- src/kernel/types/__init__.py | 2 +- .../types/deployment_follow_response.py | 33 +---------------- .../types/invocation_follow_response.py | 37 +++---------------- src/kernel/types/shared/__init__.py | 2 + src/kernel/types/shared/error.py | 21 +++++++++++ src/kernel/types/shared/error_event.py | 19 ++++++++++ 8 files changed, 55 insertions(+), 67 deletions(-) create mode 100644 src/kernel/types/shared/error.py create mode 100644 src/kernel/types/shared/error_event.py diff --git a/.stats.yml b/.stats.yml index b912099..763dad3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5d4e11bc46eeecee7363d56a9dfe946acee997d5b352c2b0a50c20e742c54d2d.yml -openapi_spec_hash: 333e53ad9c706296b9afdb8ff73bec8f -config_hash: 4e2f9aebc2153d5caf7bb8b2eb107026 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b1b412b00906fca75bfa73cff7267dbb5bf975581778072e0a90c73ad7ba9cb1.yml +openapi_spec_hash: 9b7a1b29bcb4963fe6da37005c357d27 +config_hash: df959c379e1145106030a4869b006afe diff --git a/api.md b/api.md index 9a7d9a7..b3f657c 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,7 @@ # Shared Types ```python -from kernel.types import ErrorDetail, LogEvent +from kernel.types import Error, ErrorDetail, ErrorEvent, LogEvent ``` # Deployments diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 4a5c229..ff41497 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import LogEvent as LogEvent, ErrorDetail as ErrorDetail +from .shared import Error as Error, LogEvent as LogEvent, ErrorEvent as ErrorEvent, ErrorDetail as ErrorDetail from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_persistence import BrowserPersistence as BrowserPersistence diff --git a/src/kernel/types/deployment_follow_response.py b/src/kernel/types/deployment_follow_response.py index 38afcad..e95ce26 100644 --- a/src/kernel/types/deployment_follow_response.py +++ b/src/kernel/types/deployment_follow_response.py @@ -7,16 +7,10 @@ from .._utils import PropertyInfo from .._models import BaseModel from .shared.log_event import LogEvent -from .shared.error_detail import ErrorDetail +from .shared.error_event import ErrorEvent from .deployment_state_event import DeploymentStateEvent -__all__ = [ - "DeploymentFollowResponse", - "AppVersionSummaryEvent", - "AppVersionSummaryEventAction", - "ErrorEvent", - "ErrorEventError", -] +__all__ = ["DeploymentFollowResponse", "AppVersionSummaryEvent", "AppVersionSummaryEventAction"] class AppVersionSummaryEventAction(BaseModel): @@ -50,29 +44,6 @@ class AppVersionSummaryEvent(BaseModel): """Environment variables configured for this app version""" -class ErrorEventError(BaseModel): - code: str - """Application-specific error code (machine-readable)""" - - message: str - """Human-readable error description for debugging""" - - details: Optional[List[ErrorDetail]] = None - """Additional error details (for multiple errors)""" - - inner_error: Optional[ErrorDetail] = None - - -class ErrorEvent(BaseModel): - error: ErrorEventError - - event: Literal["error"] - """Event type identifier (always "error").""" - - timestamp: datetime - """Time the error occurred.""" - - DeploymentFollowResponse: TypeAlias = Annotated[ Union[LogEvent, DeploymentStateEvent, AppVersionSummaryEvent, ErrorEvent], PropertyInfo(discriminator="event") ] diff --git a/src/kernel/types/invocation_follow_response.py b/src/kernel/types/invocation_follow_response.py index b1693a1..1abbafc 100644 --- a/src/kernel/types/invocation_follow_response.py +++ b/src/kernel/types/invocation_follow_response.py @@ -1,41 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, Annotated, TypeAlias +from typing import Union +from typing_extensions import Annotated, TypeAlias from .._utils import PropertyInfo -from .._models import BaseModel from .shared.log_event import LogEvent -from .shared.error_detail import ErrorDetail +from .shared.error_event import ErrorEvent +from .deployment_state_event import DeploymentStateEvent from .invocation_state_event import InvocationStateEvent -__all__ = ["InvocationFollowResponse", "ErrorEvent", "ErrorEventError"] - - -class ErrorEventError(BaseModel): - code: str - """Application-specific error code (machine-readable)""" - - message: str - """Human-readable error description for debugging""" - - details: Optional[List[ErrorDetail]] = None - """Additional error details (for multiple errors)""" - - inner_error: Optional[ErrorDetail] = None - - -class ErrorEvent(BaseModel): - error: ErrorEventError - - event: Literal["error"] - """Event type identifier (always "error").""" - - timestamp: datetime - """Time the error occurred.""" - +__all__ = ["InvocationFollowResponse"] InvocationFollowResponse: TypeAlias = Annotated[ - Union[LogEvent, InvocationStateEvent, ErrorEvent], PropertyInfo(discriminator="event") + Union[LogEvent, DeploymentStateEvent, InvocationStateEvent, ErrorEvent], PropertyInfo(discriminator="event") ] diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py index 1f139b0..f7c487b 100644 --- a/src/kernel/types/shared/__init__.py +++ b/src/kernel/types/shared/__init__.py @@ -1,4 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .error import Error as Error from .log_event import LogEvent as LogEvent +from .error_event import ErrorEvent as ErrorEvent from .error_detail import ErrorDetail as ErrorDetail diff --git a/src/kernel/types/shared/error.py b/src/kernel/types/shared/error.py new file mode 100644 index 0000000..47c8aae --- /dev/null +++ b/src/kernel/types/shared/error.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .error_detail import ErrorDetail + +__all__ = ["Error"] + + +class Error(BaseModel): + code: str + """Application-specific error code (machine-readable)""" + + message: str + """Human-readable error description for debugging""" + + details: Optional[List[ErrorDetail]] = None + """Additional error details (for multiple errors)""" + + inner_error: Optional[ErrorDetail] = None diff --git a/src/kernel/types/shared/error_event.py b/src/kernel/types/shared/error_event.py new file mode 100644 index 0000000..542634b --- /dev/null +++ b/src/kernel/types/shared/error_event.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime +from typing_extensions import Literal + +from .error import Error +from ..._models import BaseModel + +__all__ = ["ErrorEvent"] + + +class ErrorEvent(BaseModel): + error: Error + + event: Literal["error"] + """Event type identifier (always "error").""" + + timestamp: datetime + """Time the error occurred.""" From dff3e3965fc710beadac2410a8a065d81b889d43 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:23:13 +0000 Subject: [PATCH 18/23] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/kernel/types/invocation_follow_response.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 763dad3..1e9f62b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-b1b412b00906fca75bfa73cff7267dbb5bf975581778072e0a90c73ad7ba9cb1.yml -openapi_spec_hash: 9b7a1b29bcb4963fe6da37005c357d27 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5d4e11bc46eeecee7363d56a9dfe946acee997d5b352c2b0a50c20e742c54d2d.yml +openapi_spec_hash: 333e53ad9c706296b9afdb8ff73bec8f config_hash: df959c379e1145106030a4869b006afe diff --git a/src/kernel/types/invocation_follow_response.py b/src/kernel/types/invocation_follow_response.py index 1abbafc..e3d7e8e 100644 --- a/src/kernel/types/invocation_follow_response.py +++ b/src/kernel/types/invocation_follow_response.py @@ -6,11 +6,10 @@ from .._utils import PropertyInfo from .shared.log_event import LogEvent from .shared.error_event import ErrorEvent -from .deployment_state_event import DeploymentStateEvent from .invocation_state_event import InvocationStateEvent __all__ = ["InvocationFollowResponse"] InvocationFollowResponse: TypeAlias = Annotated[ - Union[LogEvent, DeploymentStateEvent, InvocationStateEvent, ErrorEvent], PropertyInfo(discriminator="event") + Union[LogEvent, InvocationStateEvent, ErrorEvent], PropertyInfo(discriminator="event") ] From 0c8937a4d8891357223c41fadcb05a6dd1f359b1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:25:14 +0000 Subject: [PATCH 19/23] feat(api): update via SDK Studio --- .stats.yml | 2 +- api.md | 2 +- src/kernel/types/__init__.py | 2 +- src/kernel/types/shared/__init__.py | 1 - src/kernel/types/shared/error.py | 21 --------------------- src/kernel/types/shared/error_event.py | 18 ++++++++++++++++-- 6 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 src/kernel/types/shared/error.py diff --git a/.stats.yml b/.stats.yml index 1e9f62b..71dae95 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5d4e11bc46eeecee7363d56a9dfe946acee997d5b352c2b0a50c20e742c54d2d.yml openapi_spec_hash: 333e53ad9c706296b9afdb8ff73bec8f -config_hash: df959c379e1145106030a4869b006afe +config_hash: 79af9b3bec53ee798dddcf815befa25d diff --git a/api.md b/api.md index b3f657c..4574ce7 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,7 @@ # Shared Types ```python -from kernel.types import Error, ErrorDetail, ErrorEvent, LogEvent +from kernel.types import ErrorDetail, ErrorEvent, LogEvent ``` # Deployments diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index ff41497..87e9ac8 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import Error as Error, LogEvent as LogEvent, ErrorEvent as ErrorEvent, ErrorDetail as ErrorDetail +from .shared import LogEvent as LogEvent, ErrorEvent as ErrorEvent, ErrorDetail as ErrorDetail from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_persistence import BrowserPersistence as BrowserPersistence diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py index f7c487b..45c73b3 100644 --- a/src/kernel/types/shared/__init__.py +++ b/src/kernel/types/shared/__init__.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .error import Error as Error from .log_event import LogEvent as LogEvent from .error_event import ErrorEvent as ErrorEvent from .error_detail import ErrorDetail as ErrorDetail diff --git a/src/kernel/types/shared/error.py b/src/kernel/types/shared/error.py deleted file mode 100644 index 47c8aae..0000000 --- a/src/kernel/types/shared/error.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .error_detail import ErrorDetail - -__all__ = ["Error"] - - -class Error(BaseModel): - code: str - """Application-specific error code (machine-readable)""" - - message: str - """Human-readable error description for debugging""" - - details: Optional[List[ErrorDetail]] = None - """Additional error details (for multiple errors)""" - - inner_error: Optional[ErrorDetail] = None diff --git a/src/kernel/types/shared/error_event.py b/src/kernel/types/shared/error_event.py index 542634b..172a8be 100644 --- a/src/kernel/types/shared/error_event.py +++ b/src/kernel/types/shared/error_event.py @@ -1,12 +1,26 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from datetime import datetime from typing_extensions import Literal -from .error import Error from ..._models import BaseModel +from .error_detail import ErrorDetail -__all__ = ["ErrorEvent"] +__all__ = ["ErrorEvent", "Error"] + + +class Error(BaseModel): + code: str + """Application-specific error code (machine-readable)""" + + message: str + """Human-readable error description for debugging""" + + details: Optional[List[ErrorDetail]] = None + """Additional error details (for multiple errors)""" + + inner_error: Optional[ErrorDetail] = None class ErrorEvent(BaseModel): From a81101709db8cb64b4cb6af6b749b55f86c24be6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 15:25:57 +0000 Subject: [PATCH 20/23] feat(api): update via SDK Studio --- .stats.yml | 2 +- api.md | 2 +- src/kernel/types/__init__.py | 2 +- src/kernel/types/shared/__init__.py | 1 + src/kernel/types/shared/error_event.py | 20 +++----------------- src/kernel/types/shared/error_model.py | 21 +++++++++++++++++++++ 6 files changed, 28 insertions(+), 20 deletions(-) create mode 100644 src/kernel/types/shared/error_model.py diff --git a/.stats.yml b/.stats.yml index 71dae95..ba1c7c9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-5d4e11bc46eeecee7363d56a9dfe946acee997d5b352c2b0a50c20e742c54d2d.yml openapi_spec_hash: 333e53ad9c706296b9afdb8ff73bec8f -config_hash: 79af9b3bec53ee798dddcf815befa25d +config_hash: 0fdf285ddd8dee229fd84ea57df9080f diff --git a/api.md b/api.md index 4574ce7..cb25dcb 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,7 @@ # Shared Types ```python -from kernel.types import ErrorDetail, ErrorEvent, LogEvent +from kernel.types import ErrorDetail, ErrorEvent, ErrorModel, LogEvent ``` # Deployments diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 87e9ac8..cf2dbbc 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -2,7 +2,7 @@ from __future__ import annotations -from .shared import LogEvent as LogEvent, ErrorEvent as ErrorEvent, ErrorDetail as ErrorDetail +from .shared import LogEvent as LogEvent, ErrorEvent as ErrorEvent, ErrorModel as ErrorModel, ErrorDetail as ErrorDetail from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_persistence import BrowserPersistence as BrowserPersistence diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py index 45c73b3..e444e22 100644 --- a/src/kernel/types/shared/__init__.py +++ b/src/kernel/types/shared/__init__.py @@ -2,4 +2,5 @@ from .log_event import LogEvent as LogEvent from .error_event import ErrorEvent as ErrorEvent +from .error_model import ErrorModel as ErrorModel from .error_detail import ErrorDetail as ErrorDetail diff --git a/src/kernel/types/shared/error_event.py b/src/kernel/types/shared/error_event.py index 172a8be..0041b89 100644 --- a/src/kernel/types/shared/error_event.py +++ b/src/kernel/types/shared/error_event.py @@ -1,30 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional from datetime import datetime from typing_extensions import Literal from ..._models import BaseModel -from .error_detail import ErrorDetail +from .error_model import ErrorModel -__all__ = ["ErrorEvent", "Error"] - - -class Error(BaseModel): - code: str - """Application-specific error code (machine-readable)""" - - message: str - """Human-readable error description for debugging""" - - details: Optional[List[ErrorDetail]] = None - """Additional error details (for multiple errors)""" - - inner_error: Optional[ErrorDetail] = None +__all__ = ["ErrorEvent"] class ErrorEvent(BaseModel): - error: Error + error: ErrorModel event: Literal["error"] """Event type identifier (always "error").""" diff --git a/src/kernel/types/shared/error_model.py b/src/kernel/types/shared/error_model.py new file mode 100644 index 0000000..6cb4811 --- /dev/null +++ b/src/kernel/types/shared/error_model.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel +from .error_detail import ErrorDetail + +__all__ = ["ErrorModel"] + + +class ErrorModel(BaseModel): + code: str + """Application-specific error code (machine-readable)""" + + message: str + """Human-readable error description for debugging""" + + details: Optional[List[ErrorDetail]] = None + """Additional error details (for multiple errors)""" + + inner_error: Optional[ErrorDetail] = None From 099868c0c2fbb92a4b9e97cda89bf4e71781d76f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:12:12 +0000 Subject: [PATCH 21/23] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d3c4fa..fa501ab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Kernel Python API library -[![PyPI version](https://img.shields.io/pypi/v/kernel.svg)](https://pypi.org/project/kernel/) +[![PyPI version]()](https://pypi.org/project/kernel/) The Kernel Python library provides convenient access to the Kernel REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From 53d65471447af6f764aa48bd708c540215c8fd4a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 05:49:09 +0000 Subject: [PATCH 22/23] fix(tests): fix: tests which call HTTP endpoints directly with the example parameters --- tests/test_client.py | 69 ++++++++------------------------------------ 1 file changed, 12 insertions(+), 57 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 9f38a30..dea2c81 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,9 +23,7 @@ from kernel import Kernel, AsyncKernel, APIResponseValidationError from kernel._types import Omit -from kernel._utils import maybe_transform from kernel._models import BaseModel, FinalRequestOptions -from kernel._constants import RAW_RESPONSE_HEADER from kernel._exceptions import KernelError, APIStatusError, APITimeoutError, APIResponseValidationError from kernel._base_client import ( DEFAULT_TIMEOUT, @@ -35,7 +33,6 @@ DefaultAsyncHttpxClient, make_request_options, ) -from kernel.types.browser_create_params import BrowserCreateParams from .utils import update_env @@ -722,45 +719,22 @@ def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str @pytest.mark.skip() # SDK-2615 @mock.patch("kernel._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Kernel) -> None: respx_mock.post("/browsers").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - self.client.post( - "/browsers", - body=cast( - object, - maybe_transform( - dict(invocation_id="REPLACE_ME", persistence={"id": "browser-for-user-1234"}), - BrowserCreateParams, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + client.browsers.with_streaming_response.create(invocation_id="rr33xuugxj9h0bkf1rdt2bet").__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.skip() # SDK-2615 @mock.patch("kernel._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Kernel) -> None: respx_mock.post("/browsers").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - self.client.post( - "/browsers", - body=cast( - object, - maybe_transform( - dict(invocation_id="REPLACE_ME", persistence={"id": "browser-for-user-1234"}), - BrowserCreateParams, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + client.browsers.with_streaming_response.create(invocation_id="rr33xuugxj9h0bkf1rdt2bet").__enter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1575,45 +1549,26 @@ async def test_parse_retry_after_header(self, remaining_retries: int, retry_afte @pytest.mark.skip() # SDK-2615 @mock.patch("kernel._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncKernel) -> None: respx_mock.post("/browsers").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await self.client.post( - "/browsers", - body=cast( - object, - maybe_transform( - dict(invocation_id="REPLACE_ME", persistence={"id": "browser-for-user-1234"}), - BrowserCreateParams, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) + await async_client.browsers.with_streaming_response.create( + invocation_id="rr33xuugxj9h0bkf1rdt2bet" + ).__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.skip() # SDK-2615 @mock.patch("kernel._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> None: + async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncKernel) -> None: respx_mock.post("/browsers").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await self.client.post( - "/browsers", - body=cast( - object, - maybe_transform( - dict(invocation_id="REPLACE_ME", persistence={"id": "browser-for-user-1234"}), - BrowserCreateParams, - ), - ), - cast_to=httpx.Response, - options={"headers": {RAW_RESPONSE_HEADER: "stream"}}, - ) - + await async_client.browsers.with_streaming_response.create( + invocation_id="rr33xuugxj9h0bkf1rdt2bet" + ).__aenter__() assert _get_open_connections(self.client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) From 834f1e989392f4f15b88689fef81fbe3d7b071f4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 05:49:30 +0000 Subject: [PATCH 23/23] release: 0.6.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2aca35a..4208b5c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.0" + ".": "0.6.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 462f762..25d053c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## 0.6.0 (2025-06-18) + +Full Changelog: [v0.5.0...v0.6.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.5.0...v0.6.0) + +### Features + +* **api:** update via SDK Studio ([a811017](https://github.com/onkernel/kernel-python-sdk/commit/a81101709db8cb64b4cb6af6b749b55f86c24be6)) +* **api:** update via SDK Studio ([0c8937a](https://github.com/onkernel/kernel-python-sdk/commit/0c8937a4d8891357223c41fadcb05a6dd1f359b1)) +* **api:** update via SDK Studio ([dff3e39](https://github.com/onkernel/kernel-python-sdk/commit/dff3e3965fc710beadac2410a8a065d81b889d43)) +* **api:** update via SDK Studio ([d26c519](https://github.com/onkernel/kernel-python-sdk/commit/d26c519a798d8bf66baaef49af818b4108c3d92a)) +* **api:** update via SDK Studio ([ff07935](https://github.com/onkernel/kernel-python-sdk/commit/ff0793585ded6d9ea6c50947b9915f560221ed0f)) +* **api:** update via SDK Studio ([fe8d70b](https://github.com/onkernel/kernel-python-sdk/commit/fe8d70b1f0a0725c37c794aeb5a7a466bc13cdf3)) +* **api:** update via SDK Studio ([8073db6](https://github.com/onkernel/kernel-python-sdk/commit/8073db60205835e3abb6c494e24bb034283c55f2)) +* **api:** update via SDK Studio ([c1cdbcc](https://github.com/onkernel/kernel-python-sdk/commit/c1cdbcc6e555ab5fc7ecc229095ff7d0bf272e1a)) +* **api:** update via SDK Studio ([eed8e67](https://github.com/onkernel/kernel-python-sdk/commit/eed8e6769fd4982cadb277aa4c271c211992077a)) +* **api:** update via SDK Studio ([7699111](https://github.com/onkernel/kernel-python-sdk/commit/76991114e757c0c054e89d614619e38b2ec7d918)) +* **api:** update via SDK Studio ([d51332b](https://github.com/onkernel/kernel-python-sdk/commit/d51332b18af547affb215d9a7596bbbdb7ccff24)) +* **api:** update via SDK Studio ([452e83c](https://github.com/onkernel/kernel-python-sdk/commit/452e83c41d808b97e1ff54cdfa79d74abccfc9b5)) +* **api:** update via SDK Studio ([496e5cd](https://github.com/onkernel/kernel-python-sdk/commit/496e5cd31745446c16234120f9299be4a9830bb5)) + + +### Bug Fixes + +* **client:** correctly parse binary response | stream ([0079349](https://github.com/onkernel/kernel-python-sdk/commit/007934910a1ec8e17a6be821feacef9b42a2c142)) +* **tests:** fix: tests which call HTTP endpoints directly with the example parameters ([53d6547](https://github.com/onkernel/kernel-python-sdk/commit/53d65471447af6f764aa48bd708c540215c8fd4a)) + + +### Chores + +* **ci:** enable for pull requests ([fb3fba1](https://github.com/onkernel/kernel-python-sdk/commit/fb3fba16b9149449f8327b909210d42ee7744ba4)) +* **internal:** update conftest.py ([bcfcef2](https://github.com/onkernel/kernel-python-sdk/commit/bcfcef2eb9cd584ad6ec508956d59b34211d2e14)) +* **readme:** update badges ([099868c](https://github.com/onkernel/kernel-python-sdk/commit/099868c0c2fbb92a4b9e97cda89bf4e71781d76f)) +* **tests:** add tests for httpx client instantiation & proxies ([235bf24](https://github.com/onkernel/kernel-python-sdk/commit/235bf248a71505c9d5d536f1b6a7120e43b9cedc)) +* **tests:** run tests in parallel ([83e4f2c](https://github.com/onkernel/kernel-python-sdk/commit/83e4f2c26f02a7df56917e993af1e1d85ba241e6)) + ## 0.5.0 (2025-06-03) Full Changelog: [v0.4.0...v0.5.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.4.0...v0.5.0) diff --git a/pyproject.toml b/pyproject.toml index ce8b48d..3bfd297 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.5.0" +version = "0.6.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 2c947c2..c6e626d 100644 --- a/src/kernel/_version.py +++ b/src/kernel/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "kernel" -__version__ = "0.5.0" # x-release-please-version +__version__ = "0.6.0" # x-release-please-version