diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0c2ecec6..86b0e83d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.20.0" + ".": "0.21.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 11b820d4..25e77f1e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 66 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-2af1b468584cb44aa9babbbfb82bff4055614fbb5c815084a6b7dacc1cf1a822.yml -openapi_spec_hash: 891affa2849341ea01d62011125f7edc -config_hash: 9421eb86b7f3f4b274f123279da3858e +configured_endpoints: 74 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-3db06d1628149b5ea8303f1c72250664dfd7cb4a14ceb6102f1ae6e85c92c038.yml +openapi_spec_hash: e5b3da2da328eb26d2a70e2521744c62 +config_hash: a4124701ae0a474e580d7416adbcfb00 diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c65e07..a726401d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.21.0 (2025-12-02) + +Full Changelog: [v0.20.0...v0.21.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.20.0...v0.21.0) + +### Features + +* Browser pools sdk release ([c2d7408](https://github.com/onkernel/kernel-python-sdk/commit/c2d7408a770ddd34902986015da0bfde3477f586)) +* Mason/agent auth api ([b872928](https://github.com/onkernel/kernel-python-sdk/commit/b8729284ba804461749dad0ac4613aea3c6b3ce6)) + + +### Bug Fixes + +* ensure streams are always closed ([c82f496](https://github.com/onkernel/kernel-python-sdk/commit/c82f496ba0112b195f65da9498fb22ab65d501fb)) + + +### Chores + +* add Python 3.14 classifier and testing ([9a1e7bf](https://github.com/onkernel/kernel-python-sdk/commit/9a1e7bf9c92d64da4a151dd44cc60057c75c63bf)) +* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([038b10d](https://github.com/onkernel/kernel-python-sdk/commit/038b10d52935961c37ebb0806e9b0754b4d53a20)) + ## 0.20.0 (2025-11-19) Full Changelog: [v0.19.2...v0.20.0](https://github.com/onkernel/kernel-python-sdk/compare/v0.19.2...v0.20.0) diff --git a/api.md b/api.md index afa0ddd4..fe6b45c0 100644 --- a/api.md +++ b/api.md @@ -1,7 +1,17 @@ # Shared Types ```python -from kernel.types import AppAction, ErrorDetail, ErrorEvent, ErrorModel, HeartbeatEvent, LogEvent +from kernel.types import ( + AppAction, + BrowserExtension, + BrowserProfile, + BrowserViewport, + ErrorDetail, + ErrorEvent, + ErrorModel, + HeartbeatEvent, + LogEvent, +) ``` # Deployments @@ -243,3 +253,30 @@ Methods: - client.extensions.download(id_or_name) -> BinaryAPIResponse - client.extensions.download_from_chrome_store(\*\*params) -> BinaryAPIResponse - client.extensions.upload(\*\*params) -> ExtensionUploadResponse + +# BrowserPools + +Types: + +```python +from kernel.types import ( + BrowserPool, + BrowserPoolAcquireRequest, + BrowserPoolReleaseRequest, + BrowserPoolRequest, + BrowserPoolUpdateRequest, + BrowserPoolListResponse, + BrowserPoolAcquireResponse, +) +``` + +Methods: + +- client.browser_pools.create(\*\*params) -> BrowserPool +- client.browser_pools.retrieve(id_or_name) -> BrowserPool +- client.browser_pools.update(id_or_name, \*\*params) -> BrowserPool +- client.browser_pools.list() -> BrowserPoolListResponse +- client.browser_pools.delete(id_or_name, \*\*params) -> None +- client.browser_pools.acquire(id_or_name, \*\*params) -> BrowserPoolAcquireResponse +- client.browser_pools.flush(id_or_name) -> None +- client.browser_pools.release(id_or_name, \*\*params) -> None diff --git a/pyproject.toml b/pyproject.toml index b5d3ecb5..f4bbe655 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.20.0" +version = "0.21.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", @@ -45,7 +46,7 @@ managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", diff --git a/requirements-dev.lock b/requirements-dev.lock index fc032738..b435fc70 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -72,7 +72,7 @@ mdurl==0.1.2 multidict==6.4.4 # via aiohttp # via yarl -mypy==1.14.1 +mypy==1.17.0 mypy-extensions==1.0.0 # via mypy nodeenv==1.8.0 @@ -81,6 +81,8 @@ nox==2023.4.22 packaging==23.2 # via nox # via pytest +pathspec==0.12.1 + # via mypy platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 diff --git a/requirements.lock b/requirements.lock index ed64e3db..646e8cda 100644 --- a/requirements.lock +++ b/requirements.lock @@ -55,21 +55,21 @@ multidict==6.4.4 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via kernel -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic sniffio==1.3.0 # via anyio # via kernel -typing-extensions==4.12.2 +typing-extensions==4.15.0 # via anyio # via kernel # via multidict # via pydantic # via pydantic-core # via typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic yarl==1.20.0 # via aiohttp diff --git a/src/kernel/_client.py b/src/kernel/_client.py index ea9e51b9..37ba4890 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 apps, proxies, profiles, extensions, deployments, invocations +from .resources import apps, proxies, profiles, extensions, deployments, invocations, browser_pools from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import KernelError, APIStatusError from ._base_client import ( @@ -57,6 +57,7 @@ class Kernel(SyncAPIClient): profiles: profiles.ProfilesResource proxies: proxies.ProxiesResource extensions: extensions.ExtensionsResource + browser_pools: browser_pools.BrowserPoolsResource with_raw_response: KernelWithRawResponse with_streaming_response: KernelWithStreamedResponse @@ -145,6 +146,7 @@ def __init__( self.profiles = profiles.ProfilesResource(self) self.proxies = proxies.ProxiesResource(self) self.extensions = extensions.ExtensionsResource(self) + self.browser_pools = browser_pools.BrowserPoolsResource(self) self.with_raw_response = KernelWithRawResponse(self) self.with_streaming_response = KernelWithStreamedResponse(self) @@ -263,6 +265,7 @@ class AsyncKernel(AsyncAPIClient): profiles: profiles.AsyncProfilesResource proxies: proxies.AsyncProxiesResource extensions: extensions.AsyncExtensionsResource + browser_pools: browser_pools.AsyncBrowserPoolsResource with_raw_response: AsyncKernelWithRawResponse with_streaming_response: AsyncKernelWithStreamedResponse @@ -351,6 +354,7 @@ def __init__( self.profiles = profiles.AsyncProfilesResource(self) self.proxies = proxies.AsyncProxiesResource(self) self.extensions = extensions.AsyncExtensionsResource(self) + self.browser_pools = browser_pools.AsyncBrowserPoolsResource(self) self.with_raw_response = AsyncKernelWithRawResponse(self) self.with_streaming_response = AsyncKernelWithStreamedResponse(self) @@ -470,6 +474,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithRawResponse(client.extensions) + self.browser_pools = browser_pools.BrowserPoolsResourceWithRawResponse(client.browser_pools) class AsyncKernelWithRawResponse: @@ -481,6 +486,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithRawResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithRawResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithRawResponse(client.extensions) + self.browser_pools = browser_pools.AsyncBrowserPoolsResourceWithRawResponse(client.browser_pools) class KernelWithStreamedResponse: @@ -492,6 +498,7 @@ def __init__(self, client: Kernel) -> None: self.profiles = profiles.ProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.ProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.ExtensionsResourceWithStreamingResponse(client.extensions) + self.browser_pools = browser_pools.BrowserPoolsResourceWithStreamingResponse(client.browser_pools) class AsyncKernelWithStreamedResponse: @@ -503,6 +510,7 @@ def __init__(self, client: AsyncKernel) -> None: self.profiles = profiles.AsyncProfilesResourceWithStreamingResponse(client.profiles) self.proxies = proxies.AsyncProxiesResourceWithStreamingResponse(client.proxies) self.extensions = extensions.AsyncExtensionsResourceWithStreamingResponse(client.extensions) + self.browser_pools = browser_pools.AsyncBrowserPoolsResourceWithStreamingResponse(client.browser_pools) Client = Kernel diff --git a/src/kernel/_streaming.py b/src/kernel/_streaming.py index e6d03062..369a3f6d 100644 --- a/src/kernel/_streaming.py +++ b/src/kernel/_streaming.py @@ -54,11 +54,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - response.close() + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -117,11 +118,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - await response.aclose() + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 1a28cba2..1bd01d63 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.20.0" # x-release-please-version +__version__ = "0.21.0" # x-release-please-version diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index 1b68d89f..cf08046e 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -56,6 +56,14 @@ InvocationsResourceWithStreamingResponse, AsyncInvocationsResourceWithStreamingResponse, ) +from .browser_pools import ( + BrowserPoolsResource, + AsyncBrowserPoolsResource, + BrowserPoolsResourceWithRawResponse, + AsyncBrowserPoolsResourceWithRawResponse, + BrowserPoolsResourceWithStreamingResponse, + AsyncBrowserPoolsResourceWithStreamingResponse, +) __all__ = [ "DeploymentsResource", @@ -100,4 +108,10 @@ "AsyncExtensionsResourceWithRawResponse", "ExtensionsResourceWithStreamingResponse", "AsyncExtensionsResourceWithStreamingResponse", + "BrowserPoolsResource", + "AsyncBrowserPoolsResource", + "BrowserPoolsResourceWithRawResponse", + "AsyncBrowserPoolsResourceWithRawResponse", + "BrowserPoolsResourceWithStreamingResponse", + "AsyncBrowserPoolsResourceWithStreamingResponse", ] diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py new file mode 100644 index 00000000..d085d515 --- /dev/null +++ b/src/kernel/resources/browser_pools.py @@ -0,0 +1,1022 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable + +import httpx + +from ..types import ( + browser_pool_create_params, + browser_pool_delete_params, + browser_pool_update_params, + browser_pool_acquire_params, + browser_pool_release_params, +) +from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.browser_pool import BrowserPool +from ..types.browser_pool_list_response import BrowserPoolListResponse +from ..types.browser_pool_acquire_response import BrowserPoolAcquireResponse +from ..types.shared_params.browser_profile import BrowserProfile +from ..types.shared_params.browser_viewport import BrowserViewport +from ..types.shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolsResource", "AsyncBrowserPoolsResource"] + + +class BrowserPoolsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BrowserPoolsResourceWithRawResponse: + """ + 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 BrowserPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BrowserPoolsResourceWithStreamingResponse: + """ + 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 BrowserPoolsResourceWithStreamingResponse(self) + + def create( + self, + *, + size: int, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | Omit = omit, + # 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, + ) -> BrowserPool: + """ + Create a new browser pool with the specified configuration and size. + + Args: + size: Number of browsers to create in the pool + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/browser_pools", + body=maybe_transform( + { + "size": size, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_create_params.BrowserPoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def retrieve( + self, + id_or_name: 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, + ) -> BrowserPool: + """ + Retrieve details for a single browser pool by its ID or name. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._get( + f"/browser_pools/{id_or_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def update( + self, + id_or_name: str, + *, + size: int, + discard_all_idle: bool | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | Omit = omit, + # 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, + ) -> BrowserPool: + """ + Updates the configuration used to create browsers in the pool. + + Args: + size: Number of browsers to create in the pool + + discard_all_idle: Whether to discard all idle browsers and rebuild the pool immediately. Defaults + to true. + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._patch( + f"/browser_pools/{id_or_name}", + body=maybe_transform( + { + "size": size, + "discard_all_idle": discard_all_idle, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_update_params.BrowserPoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + def list( + self, + *, + # 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, + ) -> BrowserPoolListResponse: + """List browser pools owned by the caller's organization.""" + return self._get( + "/browser_pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolListResponse, + ) + + def delete( + self, + id_or_name: str, + *, + force: bool | Omit = omit, + # 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, + ) -> None: + """Delete a browser pool and all browsers in it. + + By default, deletion is blocked if + browsers are currently leased. Use force=true to terminate leased browsers. + + Args: + force: If true, force delete even if browsers are currently leased. Leased browsers + will be terminated. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/browser_pools/{id_or_name}", + body=maybe_transform({"force": force}, browser_pool_delete_params.BrowserPoolDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def acquire( + self, + id_or_name: str, + *, + acquire_timeout_seconds: int | Omit = omit, + # 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, + ) -> BrowserPoolAcquireResponse: + """Long-polling endpoint to acquire a browser from the pool. + + Returns immediately + when a browser is available, or returns 204 No Content when the poll times out. + The client should retry the request to continue waiting for a browser. The + acquired browser will use the pool's timeout_seconds for its idle timeout. + + Args: + acquire_timeout_seconds: Maximum number of seconds to wait for a browser to be available. Defaults to the + calculated time it would take to fill the pool at the currently configured fill + rate. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._post( + f"/browser_pools/{id_or_name}/acquire", + body=maybe_transform( + {"acquire_timeout_seconds": acquire_timeout_seconds}, + browser_pool_acquire_params.BrowserPoolAcquireParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolAcquireResponse, + ) + + def flush( + self, + id_or_name: 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, + ) -> None: + """ + Destroys all idle browsers in the pool; leased browsers are not affected. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/browser_pools/{id_or_name}/flush", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def release( + self, + id_or_name: str, + *, + session_id: str, + reuse: bool | Omit = omit, + # 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, + ) -> None: + """ + Release a browser back to the pool, optionally recreating the browser instance. + + Args: + session_id: Browser session ID to release back to the pool + + reuse: Whether to reuse the browser instance or destroy it and create a new one. + Defaults to true. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + f"/browser_pools/{id_or_name}/release", + body=maybe_transform( + { + "session_id": session_id, + "reuse": reuse, + }, + browser_pool_release_params.BrowserPoolReleaseParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncBrowserPoolsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBrowserPoolsResourceWithRawResponse: + """ + 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 AsyncBrowserPoolsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBrowserPoolsResourceWithStreamingResponse: + """ + 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 AsyncBrowserPoolsResourceWithStreamingResponse(self) + + async def create( + self, + *, + size: int, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | Omit = omit, + # 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, + ) -> BrowserPool: + """ + Create a new browser pool with the specified configuration and size. + + Args: + size: Number of browsers to create in the pool + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/browser_pools", + body=await async_maybe_transform( + { + "size": size, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_create_params.BrowserPoolCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def retrieve( + self, + id_or_name: 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, + ) -> BrowserPool: + """ + Retrieve details for a single browser pool by its ID or name. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._get( + f"/browser_pools/{id_or_name}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def update( + self, + id_or_name: str, + *, + size: int, + discard_all_idle: bool | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, + fill_rate_per_minute: int | Omit = omit, + headless: bool | Omit = omit, + kiosk_mode: bool | Omit = omit, + name: str | Omit = omit, + profile: BrowserProfile | Omit = omit, + proxy_id: str | Omit = omit, + stealth: bool | Omit = omit, + timeout_seconds: int | Omit = omit, + viewport: BrowserViewport | Omit = omit, + # 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, + ) -> BrowserPool: + """ + Updates the configuration used to create browsers in the pool. + + Args: + size: Number of browsers to create in the pool + + discard_all_idle: Whether to discard all idle browsers and rebuild the pool immediately. Defaults + to true. + + extensions: List of browser extensions to load into the session. Provide each by id or name. + + fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10%. + + headless: If true, launches the browser using a headless image. Defaults to false. + + kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + + name: Optional name for the browser pool. Must be unique within the organization. + + profile: Profile selection for the browser session. Provide either id or name. If + specified, the matching profile will be loaded into the browser session. + Profiles must be created beforehand. + + proxy_id: Optional proxy to associate to the browser session. Must reference a proxy + belonging to the caller's org. + + stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + + timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, + image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._patch( + f"/browser_pools/{id_or_name}", + body=await async_maybe_transform( + { + "size": size, + "discard_all_idle": discard_all_idle, + "extensions": extensions, + "fill_rate_per_minute": fill_rate_per_minute, + "headless": headless, + "kiosk_mode": kiosk_mode, + "name": name, + "profile": profile, + "proxy_id": proxy_id, + "stealth": stealth, + "timeout_seconds": timeout_seconds, + "viewport": viewport, + }, + browser_pool_update_params.BrowserPoolUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPool, + ) + + async def list( + self, + *, + # 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, + ) -> BrowserPoolListResponse: + """List browser pools owned by the caller's organization.""" + return await self._get( + "/browser_pools", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolListResponse, + ) + + async def delete( + self, + id_or_name: str, + *, + force: bool | Omit = omit, + # 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, + ) -> None: + """Delete a browser pool and all browsers in it. + + By default, deletion is blocked if + browsers are currently leased. Use force=true to terminate leased browsers. + + Args: + force: If true, force delete even if browsers are currently leased. Leased browsers + will be terminated. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/browser_pools/{id_or_name}", + body=await async_maybe_transform({"force": force}, browser_pool_delete_params.BrowserPoolDeleteParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def acquire( + self, + id_or_name: str, + *, + acquire_timeout_seconds: int | Omit = omit, + # 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, + ) -> BrowserPoolAcquireResponse: + """Long-polling endpoint to acquire a browser from the pool. + + Returns immediately + when a browser is available, or returns 204 No Content when the poll times out. + The client should retry the request to continue waiting for a browser. The + acquired browser will use the pool's timeout_seconds for its idle timeout. + + Args: + acquire_timeout_seconds: Maximum number of seconds to wait for a browser to be available. Defaults to the + calculated time it would take to fill the pool at the currently configured fill + rate. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._post( + f"/browser_pools/{id_or_name}/acquire", + body=await async_maybe_transform( + {"acquire_timeout_seconds": acquire_timeout_seconds}, + browser_pool_acquire_params.BrowserPoolAcquireParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserPoolAcquireResponse, + ) + + async def flush( + self, + id_or_name: 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, + ) -> None: + """ + Destroys all idle browsers in the pool; leased browsers are not affected. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/browser_pools/{id_or_name}/flush", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def release( + self, + id_or_name: str, + *, + session_id: str, + reuse: bool | Omit = omit, + # 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, + ) -> None: + """ + Release a browser back to the pool, optionally recreating the browser instance. + + Args: + session_id: Browser session ID to release back to the pool + + reuse: Whether to reuse the browser instance or destroy it and create a new one. + Defaults to true. + + 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_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + f"/browser_pools/{id_or_name}/release", + body=await async_maybe_transform( + { + "session_id": session_id, + "reuse": reuse, + }, + browser_pool_release_params.BrowserPoolReleaseParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class BrowserPoolsResourceWithRawResponse: + def __init__(self, browser_pools: BrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = to_raw_response_wrapper( + browser_pools.create, + ) + self.retrieve = to_raw_response_wrapper( + browser_pools.retrieve, + ) + self.update = to_raw_response_wrapper( + browser_pools.update, + ) + self.list = to_raw_response_wrapper( + browser_pools.list, + ) + self.delete = to_raw_response_wrapper( + browser_pools.delete, + ) + self.acquire = to_raw_response_wrapper( + browser_pools.acquire, + ) + self.flush = to_raw_response_wrapper( + browser_pools.flush, + ) + self.release = to_raw_response_wrapper( + browser_pools.release, + ) + + +class AsyncBrowserPoolsResourceWithRawResponse: + def __init__(self, browser_pools: AsyncBrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = async_to_raw_response_wrapper( + browser_pools.create, + ) + self.retrieve = async_to_raw_response_wrapper( + browser_pools.retrieve, + ) + self.update = async_to_raw_response_wrapper( + browser_pools.update, + ) + self.list = async_to_raw_response_wrapper( + browser_pools.list, + ) + self.delete = async_to_raw_response_wrapper( + browser_pools.delete, + ) + self.acquire = async_to_raw_response_wrapper( + browser_pools.acquire, + ) + self.flush = async_to_raw_response_wrapper( + browser_pools.flush, + ) + self.release = async_to_raw_response_wrapper( + browser_pools.release, + ) + + +class BrowserPoolsResourceWithStreamingResponse: + def __init__(self, browser_pools: BrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = to_streamed_response_wrapper( + browser_pools.create, + ) + self.retrieve = to_streamed_response_wrapper( + browser_pools.retrieve, + ) + self.update = to_streamed_response_wrapper( + browser_pools.update, + ) + self.list = to_streamed_response_wrapper( + browser_pools.list, + ) + self.delete = to_streamed_response_wrapper( + browser_pools.delete, + ) + self.acquire = to_streamed_response_wrapper( + browser_pools.acquire, + ) + self.flush = to_streamed_response_wrapper( + browser_pools.flush, + ) + self.release = to_streamed_response_wrapper( + browser_pools.release, + ) + + +class AsyncBrowserPoolsResourceWithStreamingResponse: + def __init__(self, browser_pools: AsyncBrowserPoolsResource) -> None: + self._browser_pools = browser_pools + + self.create = async_to_streamed_response_wrapper( + browser_pools.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + browser_pools.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + browser_pools.update, + ) + self.list = async_to_streamed_response_wrapper( + browser_pools.list, + ) + self.delete = async_to_streamed_response_wrapper( + browser_pools.delete, + ) + self.acquire = async_to_streamed_response_wrapper( + browser_pools.acquire, + ) + self.flush = async_to_streamed_response_wrapper( + browser_pools.flush, + ) + self.release = async_to_streamed_response_wrapper( + browser_pools.release, + ) diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index 84a4fe48..f41b46ad 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -76,6 +76,9 @@ from ...types.browser_create_response import BrowserCreateResponse from ...types.browser_persistence_param import BrowserPersistenceParam from ...types.browser_retrieve_response import BrowserRetrieveResponse +from ...types.shared_params.browser_profile import BrowserProfile +from ...types.shared_params.browser_viewport import BrowserViewport +from ...types.shared_params.browser_extension import BrowserExtension __all__ = ["BrowsersResource", "AsyncBrowsersResource"] @@ -127,16 +130,16 @@ def with_streaming_response(self) -> BrowsersResourceWithStreamingResponse: def create( self, *, - extensions: Iterable[browser_create_params.Extension] | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, headless: bool | Omit = omit, invocation_id: str | Omit = omit, kiosk_mode: bool | Omit = omit, persistence: BrowserPersistenceParam | Omit = omit, - profile: browser_create_params.Profile | Omit = omit, + profile: BrowserProfile | Omit = omit, proxy_id: str | Omit = omit, stealth: bool | Omit = omit, timeout_seconds: int | Omit = omit, - viewport: browser_create_params.Viewport | Omit = omit, + viewport: BrowserViewport | Omit = omit, # 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, @@ -470,16 +473,16 @@ def with_streaming_response(self) -> AsyncBrowsersResourceWithStreamingResponse: async def create( self, *, - extensions: Iterable[browser_create_params.Extension] | Omit = omit, + extensions: Iterable[BrowserExtension] | Omit = omit, headless: bool | Omit = omit, invocation_id: str | Omit = omit, kiosk_mode: bool | Omit = omit, persistence: BrowserPersistenceParam | Omit = omit, - profile: browser_create_params.Profile | Omit = omit, + profile: BrowserProfile | Omit = omit, proxy_id: str | Omit = omit, stealth: bool | Omit = omit, timeout_seconds: int | Omit = omit, - viewport: browser_create_params.Viewport | Omit = omit, + viewport: BrowserViewport | Omit = omit, # 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, diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 208a8bda..45b0c4ba 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -8,15 +8,20 @@ ErrorEvent as ErrorEvent, ErrorModel as ErrorModel, ErrorDetail as ErrorDetail, + BrowserProfile as BrowserProfile, HeartbeatEvent as HeartbeatEvent, + BrowserViewport as BrowserViewport, + BrowserExtension as BrowserExtension, ) from .profile import Profile as Profile +from .browser_pool import BrowserPool as BrowserPool from .app_list_params import AppListParams as AppListParams from .app_list_response import AppListResponse as AppListResponse from .browser_list_params import BrowserListParams as BrowserListParams from .browser_persistence import BrowserPersistence as BrowserPersistence from .proxy_create_params import ProxyCreateParams as ProxyCreateParams from .proxy_list_response import ProxyListResponse as ProxyListResponse +from .browser_pool_request import BrowserPoolRequest as BrowserPoolRequest from .browser_create_params import BrowserCreateParams as BrowserCreateParams from .browser_delete_params import BrowserDeleteParams as BrowserDeleteParams from .browser_list_response import BrowserListResponse as BrowserListResponse @@ -41,13 +46,20 @@ from .browser_persistence_param import BrowserPersistenceParam as BrowserPersistenceParam from .browser_retrieve_response import BrowserRetrieveResponse as BrowserRetrieveResponse from .extension_upload_response import ExtensionUploadResponse as ExtensionUploadResponse +from .browser_pool_create_params import BrowserPoolCreateParams as BrowserPoolCreateParams +from .browser_pool_delete_params import BrowserPoolDeleteParams as BrowserPoolDeleteParams +from .browser_pool_list_response import BrowserPoolListResponse as BrowserPoolListResponse +from .browser_pool_update_params import BrowserPoolUpdateParams as BrowserPoolUpdateParams 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 .browser_pool_acquire_params import BrowserPoolAcquireParams as BrowserPoolAcquireParams +from .browser_pool_release_params import BrowserPoolReleaseParams as BrowserPoolReleaseParams from .deployment_retrieve_response import DeploymentRetrieveResponse as DeploymentRetrieveResponse from .invocation_retrieve_response import InvocationRetrieveResponse as InvocationRetrieveResponse +from .browser_pool_acquire_response import BrowserPoolAcquireResponse as BrowserPoolAcquireResponse from .browser_load_extensions_params import BrowserLoadExtensionsParams as BrowserLoadExtensionsParams from .extension_download_from_chrome_store_params import ( ExtensionDownloadFromChromeStoreParams as ExtensionDownloadFromChromeStoreParams, diff --git a/src/kernel/types/browser_create_params.py b/src/kernel/types/browser_create_params.py index 1e54ce75..d1ff7907 100644 --- a/src/kernel/types/browser_create_params.py +++ b/src/kernel/types/browser_create_params.py @@ -3,15 +3,18 @@ from __future__ import annotations from typing import Iterable -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict from .browser_persistence_param import BrowserPersistenceParam +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension -__all__ = ["BrowserCreateParams", "Extension", "Profile", "Viewport"] +__all__ = ["BrowserCreateParams"] class BrowserCreateParams(TypedDict, total=False): - extensions: Iterable[Extension] + extensions: Iterable[BrowserExtension] """List of browser extensions to load into the session. Provide each by id or name. @@ -35,7 +38,7 @@ class BrowserCreateParams(TypedDict, total=False): persistence: BrowserPersistenceParam """Optional persistence configuration for the browser session.""" - profile: Profile + profile: BrowserProfile """Profile selection for the browser session. Provide either id or name. If specified, the matching profile will be loaded @@ -64,7 +67,7 @@ class BrowserCreateParams(TypedDict, total=False): specified value. """ - viewport: Viewport + viewport: BrowserViewport """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport @@ -75,45 +78,3 @@ class BrowserCreateParams(TypedDict, total=False): configuration exactly. Note: Higher resolutions may affect the responsiveness of live view browser """ - - -class Extension(TypedDict, total=False): - id: str - """Extension ID to load for this browser session""" - - name: str - """Extension name to load for this browser session (instead of id). - - Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. - """ - - -class Profile(TypedDict, total=False): - id: str - """Profile ID to load for this browser session""" - - name: str - """Profile name to load for this browser session (instead of id). - - Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. - """ - - save_changes: bool - """ - If true, save changes made during the session back to the profile when the - session ends. - """ - - -class Viewport(TypedDict, total=False): - height: Required[int] - """Browser window height in pixels.""" - - width: Required[int] - """Browser window width in pixels.""" - - refresh_rate: int - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ diff --git a/src/kernel/types/browser_create_response.py b/src/kernel/types/browser_create_response.py index 21041eaa..0a5f33d4 100644 --- a/src/kernel/types/browser_create_response.py +++ b/src/kernel/types/browser_create_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserCreateResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserCreateResponse"] class BrowserCreateResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserCreateResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/browser_list_response.py b/src/kernel/types/browser_list_response.py index 74978690..d6397291 100644 --- a/src/kernel/types/browser_list_response.py +++ b/src/kernel/types/browser_list_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserListResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserListResponse"] class BrowserListResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserListResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/browser_pool.py b/src/kernel/types/browser_pool.py new file mode 100644 index 00000000..5fd30dca --- /dev/null +++ b/src/kernel/types/browser_pool.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .._models import BaseModel +from .browser_pool_request import BrowserPoolRequest + +__all__ = ["BrowserPool"] + + +class BrowserPool(BaseModel): + id: str + """Unique identifier for the browser pool""" + + acquired_count: int + """Number of browsers currently acquired from the pool""" + + available_count: int + """Number of browsers currently available in the pool""" + + browser_pool_config: BrowserPoolRequest + """Configuration used to create all browsers in this pool""" + + created_at: datetime + """Timestamp when the browser pool was created""" + + name: Optional[str] = None + """Browser pool name, if set""" diff --git a/src/kernel/types/browser_pool_acquire_params.py b/src/kernel/types/browser_pool_acquire_params.py new file mode 100644 index 00000000..d0df921a --- /dev/null +++ b/src/kernel/types/browser_pool_acquire_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserPoolAcquireParams"] + + +class BrowserPoolAcquireParams(TypedDict, total=False): + acquire_timeout_seconds: int + """Maximum number of seconds to wait for a browser to be available. + + Defaults to the calculated time it would take to fill the pool at the currently + configured fill rate. + """ diff --git a/src/kernel/types/browser_pool_acquire_response.py b/src/kernel/types/browser_pool_acquire_response.py new file mode 100644 index 00000000..76ad037b --- /dev/null +++ b/src/kernel/types/browser_pool_acquire_response.py @@ -0,0 +1,64 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .profile import Profile +from .._models import BaseModel +from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport + +__all__ = ["BrowserPoolAcquireResponse"] + + +class BrowserPoolAcquireResponse(BaseModel): + cdp_ws_url: str + """Websocket URL for Chrome DevTools Protocol connections to the browser session""" + + created_at: datetime + """When the browser session was created.""" + + headless: bool + """Whether the browser session is running in headless mode.""" + + session_id: str + """Unique identifier for the browser session""" + + stealth: bool + """Whether the browser session is running in stealth mode.""" + + timeout_seconds: int + """The number of seconds of inactivity before the browser session is terminated.""" + + browser_live_view_url: Optional[str] = None + """Remote URL for live viewing the browser session. + + Only available for non-headless browsers. + """ + + deleted_at: Optional[datetime] = None + """When the browser session was soft-deleted. Only present for deleted sessions.""" + + kiosk_mode: Optional[bool] = None + """Whether the browser session is running in kiosk mode.""" + + persistence: Optional[BrowserPersistence] = None + """Optional persistence configuration for the browser session.""" + + profile: Optional[Profile] = None + """Browser profile metadata.""" + + proxy_id: Optional[str] = None + """ID of the proxy associated with this browser session, if any.""" + + viewport: Optional[BrowserViewport] = None + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + """ diff --git a/src/kernel/types/browser_pool_create_params.py b/src/kernel/types/browser_pool_create_params.py new file mode 100644 index 00000000..c7f87c64 --- /dev/null +++ b/src/kernel/types/browser_pool_create_params.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolCreateParams"] + + +class BrowserPoolCreateParams(TypedDict, total=False): + size: Required[int] + """Number of browsers to create in the pool""" + + extensions: Iterable[BrowserExtension] + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: int + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: bool + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: bool + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: str + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: BrowserProfile + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: str + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: bool + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: int + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: BrowserViewport + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + """ diff --git a/src/kernel/types/browser_pool_delete_params.py b/src/kernel/types/browser_pool_delete_params.py new file mode 100644 index 00000000..0a63c0f1 --- /dev/null +++ b/src/kernel/types/browser_pool_delete_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserPoolDeleteParams"] + + +class BrowserPoolDeleteParams(TypedDict, total=False): + force: bool + """If true, force delete even if browsers are currently leased. + + Leased browsers will be terminated. + """ diff --git a/src/kernel/types/browser_pool_list_response.py b/src/kernel/types/browser_pool_list_response.py new file mode 100644 index 00000000..a11c4de2 --- /dev/null +++ b/src/kernel/types/browser_pool_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .browser_pool import BrowserPool + +__all__ = ["BrowserPoolListResponse"] + +BrowserPoolListResponse: TypeAlias = List[BrowserPool] diff --git a/src/kernel/types/browser_pool_release_params.py b/src/kernel/types/browser_pool_release_params.py new file mode 100644 index 00000000..104b0b0c --- /dev/null +++ b/src/kernel/types/browser_pool_release_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrowserPoolReleaseParams"] + + +class BrowserPoolReleaseParams(TypedDict, total=False): + session_id: Required[str] + """Browser session ID to release back to the pool""" + + reuse: bool + """Whether to reuse the browser instance or destroy it and create a new one. + + Defaults to true. + """ diff --git a/src/kernel/types/browser_pool_request.py b/src/kernel/types/browser_pool_request.py new file mode 100644 index 00000000..c25b3a55 --- /dev/null +++ b/src/kernel/types/browser_pool_request.py @@ -0,0 +1,73 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel +from .shared.browser_profile import BrowserProfile +from .shared.browser_viewport import BrowserViewport +from .shared.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolRequest"] + + +class BrowserPoolRequest(BaseModel): + size: int + """Number of browsers to create in the pool""" + + extensions: Optional[List[BrowserExtension]] = None + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: Optional[int] = None + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: Optional[bool] = None + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: Optional[bool] = None + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: Optional[str] = None + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: Optional[BrowserProfile] = None + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: Optional[str] = None + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: Optional[bool] = None + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: Optional[int] = None + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: Optional[BrowserViewport] = None + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + """ diff --git a/src/kernel/types/browser_pool_update_params.py b/src/kernel/types/browser_pool_update_params.py new file mode 100644 index 00000000..ed9a7e84 --- /dev/null +++ b/src/kernel/types/browser_pool_update_params.py @@ -0,0 +1,81 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable +from typing_extensions import Required, TypedDict + +from .shared_params.browser_profile import BrowserProfile +from .shared_params.browser_viewport import BrowserViewport +from .shared_params.browser_extension import BrowserExtension + +__all__ = ["BrowserPoolUpdateParams"] + + +class BrowserPoolUpdateParams(TypedDict, total=False): + size: Required[int] + """Number of browsers to create in the pool""" + + discard_all_idle: bool + """Whether to discard all idle browsers and rebuild the pool immediately. + + Defaults to true. + """ + + extensions: Iterable[BrowserExtension] + """List of browser extensions to load into the session. + + Provide each by id or name. + """ + + fill_rate_per_minute: int + """Percentage of the pool to fill per minute. Defaults to 10%.""" + + headless: bool + """If true, launches the browser using a headless image. Defaults to false.""" + + kiosk_mode: bool + """ + If true, launches the browser in kiosk mode to hide address bar and tabs in live + view. + """ + + name: str + """Optional name for the browser pool. Must be unique within the organization.""" + + profile: BrowserProfile + """Profile selection for the browser session. + + Provide either id or name. If specified, the matching profile will be loaded + into the browser session. Profiles must be created beforehand. + """ + + proxy_id: str + """Optional proxy to associate to the browser session. + + Must reference a proxy belonging to the caller's org. + """ + + stealth: bool + """ + If true, launches the browser in stealth mode to reduce detection by anti-bot + mechanisms. + """ + + timeout_seconds: int + """ + Default idle timeout in seconds for browsers acquired from this pool before they + are destroyed. Defaults to 600 seconds if not specified + """ + + viewport: BrowserViewport + """Initial browser window size in pixels with optional refresh rate. + + If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport + configurations are supported. The server will reject unsupported combinations. + Supported resolutions are: 2560x1440@10, 1920x1080@25, 1920x1200@25, + 1440x900@25, 1024x768@60, 1200x800@60 If refresh_rate is not provided, it will + be automatically determined from the width and height if they match a supported + configuration exactly. Note: Higher resolutions may affect the responsiveness of + live view browser + """ diff --git a/src/kernel/types/browser_retrieve_response.py b/src/kernel/types/browser_retrieve_response.py index 527386da..111149b3 100644 --- a/src/kernel/types/browser_retrieve_response.py +++ b/src/kernel/types/browser_retrieve_response.py @@ -6,22 +6,9 @@ from .profile import Profile from .._models import BaseModel from .browser_persistence import BrowserPersistence +from .shared.browser_viewport import BrowserViewport -__all__ = ["BrowserRetrieveResponse", "Viewport"] - - -class Viewport(BaseModel): - height: int - """Browser window height in pixels.""" - - width: int - """Browser window width in pixels.""" - - refresh_rate: Optional[int] = None - """Display refresh rate in Hz. - - If omitted, automatically determined from width and height. - """ +__all__ = ["BrowserRetrieveResponse"] class BrowserRetrieveResponse(BaseModel): @@ -64,7 +51,7 @@ class BrowserRetrieveResponse(BaseModel): proxy_id: Optional[str] = None """ID of the proxy associated with this browser session, if any.""" - viewport: Optional[Viewport] = None + viewport: Optional[BrowserViewport] = None """Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (commonly 1024x768@60). Only specific viewport diff --git a/src/kernel/types/shared/__init__.py b/src/kernel/types/shared/__init__.py index ea360f12..6b649199 100644 --- a/src/kernel/types/shared/__init__.py +++ b/src/kernel/types/shared/__init__.py @@ -5,4 +5,7 @@ from .error_event import ErrorEvent as ErrorEvent from .error_model import ErrorModel as ErrorModel from .error_detail import ErrorDetail as ErrorDetail +from .browser_profile import BrowserProfile as BrowserProfile from .heartbeat_event import HeartbeatEvent as HeartbeatEvent +from .browser_viewport import BrowserViewport as BrowserViewport +from .browser_extension import BrowserExtension as BrowserExtension diff --git a/src/kernel/types/shared/browser_extension.py b/src/kernel/types/shared/browser_extension.py new file mode 100644 index 00000000..7bc1a5ff --- /dev/null +++ b/src/kernel/types/shared/browser_extension.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserExtension"] + + +class BrowserExtension(BaseModel): + id: Optional[str] = None + """Extension ID to load for this browser session""" + + name: Optional[str] = None + """Extension name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ diff --git a/src/kernel/types/shared/browser_profile.py b/src/kernel/types/shared/browser_profile.py new file mode 100644 index 00000000..5f790ccb --- /dev/null +++ b/src/kernel/types/shared/browser_profile.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserProfile"] + + +class BrowserProfile(BaseModel): + id: Optional[str] = None + """Profile ID to load for this browser session""" + + name: Optional[str] = None + """Profile name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ + + save_changes: Optional[bool] = None + """ + If true, save changes made during the session back to the profile when the + session ends. + """ diff --git a/src/kernel/types/shared/browser_viewport.py b/src/kernel/types/shared/browser_viewport.py new file mode 100644 index 00000000..abffcc29 --- /dev/null +++ b/src/kernel/types/shared/browser_viewport.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["BrowserViewport"] + + +class BrowserViewport(BaseModel): + height: int + """Browser window height in pixels.""" + + width: int + """Browser window width in pixels.""" + + refresh_rate: Optional[int] = None + """Display refresh rate in Hz. + + If omitted, automatically determined from width and height. + """ diff --git a/src/kernel/types/shared_params/__init__.py b/src/kernel/types/shared_params/__init__.py new file mode 100644 index 00000000..de63c649 --- /dev/null +++ b/src/kernel/types/shared_params/__init__.py @@ -0,0 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .browser_profile import BrowserProfile as BrowserProfile +from .browser_viewport import BrowserViewport as BrowserViewport +from .browser_extension import BrowserExtension as BrowserExtension diff --git a/src/kernel/types/shared_params/browser_extension.py b/src/kernel/types/shared_params/browser_extension.py new file mode 100644 index 00000000..d81ac708 --- /dev/null +++ b/src/kernel/types/shared_params/browser_extension.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserExtension"] + + +class BrowserExtension(TypedDict, total=False): + id: str + """Extension ID to load for this browser session""" + + name: str + """Extension name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ diff --git a/src/kernel/types/shared_params/browser_profile.py b/src/kernel/types/shared_params/browser_profile.py new file mode 100644 index 00000000..e1027d22 --- /dev/null +++ b/src/kernel/types/shared_params/browser_profile.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["BrowserProfile"] + + +class BrowserProfile(TypedDict, total=False): + id: str + """Profile ID to load for this browser session""" + + name: str + """Profile name to load for this browser session (instead of id). + + Must be 1-255 characters, using letters, numbers, dots, underscores, or hyphens. + """ + + save_changes: bool + """ + If true, save changes made during the session back to the profile when the + session ends. + """ diff --git a/src/kernel/types/shared_params/browser_viewport.py b/src/kernel/types/shared_params/browser_viewport.py new file mode 100644 index 00000000..b7cb2f0f --- /dev/null +++ b/src/kernel/types/shared_params/browser_viewport.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BrowserViewport"] + + +class BrowserViewport(TypedDict, total=False): + height: Required[int] + """Browser window height in pixels.""" + + width: Required[int] + """Browser window width in pixels.""" + + refresh_rate: int + """Display refresh rate in Hz. + + If omitted, automatically determined from width and height. + """ diff --git a/tests/api_resources/test_browser_pools.py b/tests/api_resources/test_browser_pools.py new file mode 100644 index 00000000..6a8f164e --- /dev/null +++ b/tests/api_resources/test_browser_pools.py @@ -0,0 +1,856 @@ +# 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 ( + BrowserPool, + BrowserPoolListResponse, + BrowserPoolAcquireResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBrowserPools: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create(self, client: Kernel) -> None: + browser_pool = client.browser_pools.create( + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.create( + size=10, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_create(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.create( + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.create( + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + browser_pool = client.browser_pools.retrieve( + "id_or_name", + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update(self, client: Kernel) -> None: + browser_pool = client.browser_pools.update( + id_or_name="id_or_name", + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.update( + id_or_name="id_or_name", + size=10, + discard_all_idle=False, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_update(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.update( + id_or_name="id_or_name", + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.update( + id_or_name="id_or_name", + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_update(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.update( + id_or_name="", + size=10, + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + browser_pool = client.browser_pools.list() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete(self, client: Kernel) -> None: + browser_pool = client.browser_pools.delete( + id_or_name="id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.delete( + id_or_name="id_or_name", + force=True, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.delete( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.delete( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_delete(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.delete( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_acquire(self, client: Kernel) -> None: + browser_pool = client.browser_pools.acquire( + id_or_name="id_or_name", + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_acquire_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.acquire( + id_or_name="id_or_name", + acquire_timeout_seconds=0, + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_acquire(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.acquire( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_acquire(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.acquire( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_acquire(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.acquire( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_flush(self, client: Kernel) -> None: + browser_pool = client.browser_pools.flush( + "id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_flush(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.flush( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_flush(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.flush( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_flush(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.flush( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_release(self, client: Kernel) -> None: + browser_pool = client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_release_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + reuse=False, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_release(self, client: Kernel) -> None: + response = client.browser_pools.with_raw_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_release(self, client: Kernel) -> None: + with client.browser_pools.with_streaming_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_release(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.browser_pools.with_raw_response.release( + id_or_name="", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + +class TestAsyncBrowserPools: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.create( + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.create( + size=10, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.create( + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.create( + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.retrieve( + "id_or_name", + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @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_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.update( + id_or_name="id_or_name", + size=10, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.update( + id_or_name="id_or_name", + size=10, + discard_all_idle=False, + extensions=[ + { + "id": "id", + "name": "name", + } + ], + fill_rate_per_minute=0, + headless=False, + kiosk_mode=True, + name="my-pool", + profile={ + "id": "id", + "name": "name", + "save_changes": True, + }, + proxy_id="proxy_id", + stealth=True, + timeout_seconds=60, + viewport={ + "height": 800, + "width": 1280, + "refresh_rate": 60, + }, + ) + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.update( + id_or_name="id_or_name", + size=10, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.update( + id_or_name="id_or_name", + size=10, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPool, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @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_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.update( + id_or_name="", + size=10, + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.list() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.delete( + id_or_name="id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.delete( + id_or_name="id_or_name", + force=True, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.delete( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.delete( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.delete( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_acquire(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.acquire( + id_or_name="id_or_name", + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_acquire_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.acquire( + id_or_name="id_or_name", + acquire_timeout_seconds=0, + ) + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_acquire(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.acquire( + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_acquire(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.acquire( + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert_matches_type(BrowserPoolAcquireResponse, browser_pool, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_acquire(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.acquire( + id_or_name="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_flush(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.flush( + "id_or_name", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_flush(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.flush( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_flush(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.flush( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_flush(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.flush( + "", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_release(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_release_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + reuse=False, + ) + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_release(self, async_client: AsyncKernel) -> None: + response = await async_client.browser_pools.with_raw_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser_pool = await response.parse() + assert browser_pool is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_release(self, async_client: AsyncKernel) -> None: + async with async_client.browser_pools.with_streaming_response.release( + id_or_name="id_or_name", + session_id="ts8iy3sg25ibheguyni2lg9t", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser_pool = await response.parse() + assert browser_pool is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_release(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.browser_pools.with_raw_response.release( + id_or_name="", + session_id="ts8iy3sg25ibheguyni2lg9t", + )