From 7ff0bdf181029f0711b694fb6498fbc75183b0f3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:04:44 +0000 Subject: [PATCH 1/5] feat: api: paginate GET /proxies --- .stats.yml | 6 +- api.md | 2 +- src/kernel/resources/proxies.py | 83 +++++++++++++++++++++---- src/kernel/types/__init__.py | 1 + src/kernel/types/proxy_list_params.py | 15 +++++ src/kernel/types/proxy_list_response.py | 42 ++++++------- tests/api_resources/test_proxies.py | 31 +++++++-- 7 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 src/kernel/types/proxy_list_params.py diff --git a/.stats.yml b/.stats.yml index 27228661..032ac8ce 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-33e46e6a0095c2ec39a51860ee4e133c5a21a80a90cbe9e52953c07e5e0295de.yml -openapi_spec_hash: 4aa466b9af39768b65a44b68ae0d1f6e -config_hash: ede72e4ae65cc5a6d6927938b3455c46 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-f3e52a8a9d9e37f8b527bdcce63b39cf8807d138cf3570c9954ba7f42ef02375.yml +openapi_spec_hash: 2b787691eba1bb7bafb553528c09d5c0 +config_hash: e12afec516ced9520590c7a05af7a6f7 diff --git a/api.md b/api.md index a7fda470..1cc2b82f 100644 --- a/api.md +++ b/api.md @@ -324,7 +324,7 @@ Methods: - client.proxies.create(\*\*params) -> ProxyCreateResponse - client.proxies.retrieve(id) -> ProxyRetrieveResponse -- client.proxies.list() -> ProxyListResponse +- client.proxies.list(\*\*params) -> SyncOffsetPagination[ProxyListResponse] - client.proxies.delete(id) -> None - client.proxies.check(id, \*\*params) -> ProxyCheckResponse diff --git a/src/kernel/resources/proxies.py b/src/kernel/resources/proxies.py index 501a2e88..2239a854 100644 --- a/src/kernel/resources/proxies.py +++ b/src/kernel/resources/proxies.py @@ -6,7 +6,7 @@ import httpx -from ..types import proxy_check_params, proxy_create_params +from ..types import proxy_list_params, proxy_check_params, proxy_create_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property @@ -17,7 +17,8 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from .._base_client import make_request_options +from ..pagination import SyncOffsetPagination, AsyncOffsetPagination +from .._base_client import AsyncPaginator, make_request_options from ..types.proxy_list_response import ProxyListResponse from ..types.proxy_check_response import ProxyCheckResponse from ..types.proxy_create_response import ProxyCreateResponse @@ -140,20 +141,48 @@ def retrieve( def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> ProxyListResponse: - """List proxies owned by the caller's organization.""" - return self._get( + ) -> SyncOffsetPagination[ProxyListResponse]: + """ + List proxies owned by the caller's organization. + + Args: + limit: Limit the number of proxies to return. + + offset: Offset the number of proxies to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/proxies", + page=SyncOffsetPagination[ProxyListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + proxy_list_params.ProxyListParams, + ), ), - cast_to=ProxyListResponse, + model=ProxyListResponse, ) def delete( @@ -357,23 +386,51 @@ async def retrieve( cast_to=ProxyRetrieveResponse, ) - async def list( + def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> ProxyListResponse: - """List proxies owned by the caller's organization.""" - return await self._get( + ) -> AsyncPaginator[ProxyListResponse, AsyncOffsetPagination[ProxyListResponse]]: + """ + List proxies owned by the caller's organization. + + Args: + limit: Limit the number of proxies to return. + + offset: Offset the number of proxies to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/proxies", + page=AsyncOffsetPagination[ProxyListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + proxy_list_params.ProxyListParams, + ), ), - cast_to=ProxyListResponse, + model=ProxyListResponse, ) async def delete( diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index fb6fd589..bdc65fdf 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -25,6 +25,7 @@ from .created_api_key import CreatedAPIKey as CreatedAPIKey from .browser_pool_ref import BrowserPoolRef as BrowserPoolRef from .app_list_response import AppListResponse as AppListResponse +from .proxy_list_params import ProxyListParams as ProxyListParams from .proxy_check_params import ProxyCheckParams as ProxyCheckParams from .api_key_list_params import APIKeyListParams as APIKeyListParams from .browser_curl_params import BrowserCurlParams as BrowserCurlParams diff --git a/src/kernel/types/proxy_list_params.py b/src/kernel/types/proxy_list_params.py new file mode 100644 index 00000000..78972bcb --- /dev/null +++ b/src/kernel/types/proxy_list_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__ = ["ProxyListParams"] + + +class ProxyListParams(TypedDict, total=False): + limit: int + """Limit the number of proxies to return.""" + + offset: int + """Offset the number of proxies to return.""" diff --git a/src/kernel/types/proxy_list_response.py b/src/kernel/types/proxy_list_response.py index d1ddc079..6d40a8a4 100644 --- a/src/kernel/types/proxy_list_response.py +++ b/src/kernel/types/proxy_list_response.py @@ -8,31 +8,30 @@ __all__ = [ "ProxyListResponse", - "ProxyListResponseItem", - "ProxyListResponseItemConfig", - "ProxyListResponseItemConfigDatacenterProxyConfig", - "ProxyListResponseItemConfigIspProxyConfig", - "ProxyListResponseItemConfigResidentialProxyConfig", - "ProxyListResponseItemConfigMobileProxyConfig", - "ProxyListResponseItemConfigCustomProxyConfig", + "Config", + "ConfigDatacenterProxyConfig", + "ConfigIspProxyConfig", + "ConfigResidentialProxyConfig", + "ConfigMobileProxyConfig", + "ConfigCustomProxyConfig", ] -class ProxyListResponseItemConfigDatacenterProxyConfig(BaseModel): +class ConfigDatacenterProxyConfig(BaseModel): """Configuration for a datacenter proxy.""" country: Optional[str] = None """ISO 3166 country code. Defaults to US if not provided.""" -class ProxyListResponseItemConfigIspProxyConfig(BaseModel): +class ConfigIspProxyConfig(BaseModel): """Configuration for an ISP proxy.""" country: Optional[str] = None """ISO 3166 country code. Defaults to US if not provided.""" -class ProxyListResponseItemConfigResidentialProxyConfig(BaseModel): +class ConfigResidentialProxyConfig(BaseModel): """Configuration for residential proxies.""" asn: Optional[str] = None @@ -57,7 +56,7 @@ class ProxyListResponseItemConfigResidentialProxyConfig(BaseModel): """US ZIP code.""" -class ProxyListResponseItemConfigMobileProxyConfig(BaseModel): +class ConfigMobileProxyConfig(BaseModel): """Configuration for mobile proxies.""" city: Optional[str] = None @@ -70,7 +69,7 @@ class ProxyListResponseItemConfigMobileProxyConfig(BaseModel): """US-only state code. Mobile carrier routing can make observed geo vary.""" -class ProxyListResponseItemConfigCustomProxyConfig(BaseModel): +class ConfigCustomProxyConfig(BaseModel): """Configuration for a custom proxy (e.g., private proxy server).""" host: str @@ -86,16 +85,16 @@ class ProxyListResponseItemConfigCustomProxyConfig(BaseModel): """Username for proxy authentication.""" -ProxyListResponseItemConfig: TypeAlias = Union[ - ProxyListResponseItemConfigDatacenterProxyConfig, - ProxyListResponseItemConfigIspProxyConfig, - ProxyListResponseItemConfigResidentialProxyConfig, - ProxyListResponseItemConfigMobileProxyConfig, - ProxyListResponseItemConfigCustomProxyConfig, +Config: TypeAlias = Union[ + ConfigDatacenterProxyConfig, + ConfigIspProxyConfig, + ConfigResidentialProxyConfig, + ConfigMobileProxyConfig, + ConfigCustomProxyConfig, ] -class ProxyListResponseItem(BaseModel): +class ProxyListResponse(BaseModel): """Configuration for routing traffic through a proxy.""" type: Literal["datacenter", "isp", "residential", "mobile", "custom"] @@ -110,7 +109,7 @@ class ProxyListResponseItem(BaseModel): bypass_hosts: Optional[List[str]] = None """Hostnames that should bypass the parent proxy and connect directly.""" - config: Optional[ProxyListResponseItemConfig] = None + config: Optional[Config] = None """Configuration specific to the selected proxy `type`.""" ip_address: Optional[str] = None @@ -127,6 +126,3 @@ class ProxyListResponseItem(BaseModel): status: Optional[Literal["available", "unavailable"]] = None """Current health status of the proxy.""" - - -ProxyListResponse: TypeAlias = List[ProxyListResponseItem] diff --git a/tests/api_resources/test_proxies.py b/tests/api_resources/test_proxies.py index fd8080ee..64cb90b9 100644 --- a/tests/api_resources/test_proxies.py +++ b/tests/api_resources/test_proxies.py @@ -15,6 +15,7 @@ ProxyCreateResponse, ProxyRetrieveResponse, ) +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -114,7 +115,16 @@ def test_path_params_retrieve(self, client: Kernel) -> None: @parametrize def test_method_list(self, client: Kernel) -> None: proxy = client.proxies.list() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + proxy = client.proxies.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -124,7 +134,7 @@ def test_raw_response_list(self, client: Kernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" proxy = response.parse() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -134,7 +144,7 @@ def test_streaming_response_list(self, client: Kernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" proxy = response.parse() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(SyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) assert cast(Any, response.is_closed) is True @@ -329,7 +339,16 @@ async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: @parametrize async def test_method_list(self, async_client: AsyncKernel) -> None: proxy = await async_client.proxies.list() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + proxy = await async_client.proxies.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -339,7 +358,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" proxy = await response.parse() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -349,7 +368,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" proxy = await response.parse() - assert_matches_type(ProxyListResponse, proxy, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ProxyListResponse], proxy, path=["response"]) assert cast(Any, response.is_closed) is True From c25d693e310a1035d74654018f68b311f37545d0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:54:03 +0000 Subject: [PATCH 2/5] feat: api: paginate GET /browser_pools --- .stats.yml | 6 +- api.md | 4 +- src/kernel/resources/browser_pools.py | 83 ++++++++++++++++--- src/kernel/types/__init__.py | 2 +- src/kernel/types/browser_pool_list_params.py | 15 ++++ .../types/browser_pool_list_response.py | 10 --- tests/api_resources/test_browser_pools.py | 32 +++++-- 7 files changed, 116 insertions(+), 36 deletions(-) create mode 100644 src/kernel/types/browser_pool_list_params.py delete mode 100644 src/kernel/types/browser_pool_list_response.py diff --git a/.stats.yml b/.stats.yml index 032ac8ce..d6e38f27 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-f3e52a8a9d9e37f8b527bdcce63b39cf8807d138cf3570c9954ba7f42ef02375.yml -openapi_spec_hash: 2b787691eba1bb7bafb553528c09d5c0 -config_hash: e12afec516ced9520590c7a05af7a6f7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e5524e6eeeedc614c05bf19896f1ce6c4f8a113de85c02952d6874d579651f70.yml +openapi_spec_hash: 7815a189a50e6aa9e283213cc78d041c +config_hash: 453b25a35834fd59a55a2315d1d50746 diff --git a/api.md b/api.md index 1cc2b82f..8a6b8c6e 100644 --- a/api.md +++ b/api.md @@ -349,7 +349,7 @@ Methods: Types: ```python -from kernel.types import BrowserPool, BrowserPoolListResponse, BrowserPoolAcquireResponse +from kernel.types import BrowserPool, BrowserPoolAcquireResponse ``` Methods: @@ -357,7 +357,7 @@ 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.list(\*\*params) -> SyncOffsetPagination[BrowserPool] - 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 diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py index 64751271..203e22ad 100644 --- a/src/kernel/resources/browser_pools.py +++ b/src/kernel/resources/browser_pools.py @@ -7,6 +7,7 @@ import httpx from ..types import ( + browser_pool_list_params, browser_pool_create_params, browser_pool_delete_params, browser_pool_update_params, @@ -23,9 +24,9 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from .._base_client import make_request_options +from ..pagination import SyncOffsetPagination, AsyncOffsetPagination +from .._base_client import AsyncPaginator, 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 @@ -326,20 +327,48 @@ def update( def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> BrowserPoolListResponse: - """List browser pools owned by the caller's organization.""" - return self._get( + ) -> SyncOffsetPagination[BrowserPool]: + """ + List browser pools owned by the caller's organization. + + Args: + limit: Limit the number of browser pools to return. + + offset: Offset the number of browser pools to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/browser_pools", + page=SyncOffsetPagination[BrowserPool], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + browser_pool_list_params.BrowserPoolListParams, + ), ), - cast_to=BrowserPoolListResponse, + model=BrowserPool, ) def delete( @@ -801,23 +830,51 @@ async def update( cast_to=BrowserPool, ) - async def list( + def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> BrowserPoolListResponse: - """List browser pools owned by the caller's organization.""" - return await self._get( + ) -> AsyncPaginator[BrowserPool, AsyncOffsetPagination[BrowserPool]]: + """ + List browser pools owned by the caller's organization. + + Args: + limit: Limit the number of browser pools to return. + + offset: Offset the number of browser pools to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/browser_pools", + page=AsyncOffsetPagination[BrowserPool], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + browser_pool_list_params.BrowserPoolListParams, + ), ), - cast_to=BrowserPoolListResponse, + model=BrowserPool, ) async def delete( diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index bdc65fdf..ae16742d 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -57,6 +57,7 @@ from .extension_list_response import ExtensionListResponse as ExtensionListResponse from .extension_upload_params import ExtensionUploadParams as ExtensionUploadParams from .proxy_retrieve_response import ProxyRetrieveResponse as ProxyRetrieveResponse +from .browser_pool_list_params import BrowserPoolListParams as BrowserPoolListParams from .credential_create_params import CredentialCreateParams as CredentialCreateParams from .credential_provider_item import CredentialProviderItem as CredentialProviderItem from .credential_update_params import CredentialUpdateParams as CredentialUpdateParams @@ -71,7 +72,6 @@ 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 diff --git a/src/kernel/types/browser_pool_list_params.py b/src/kernel/types/browser_pool_list_params.py new file mode 100644 index 00000000..f8111e3e --- /dev/null +++ b/src/kernel/types/browser_pool_list_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__ = ["BrowserPoolListParams"] + + +class BrowserPoolListParams(TypedDict, total=False): + limit: int + """Limit the number of browser pools to return.""" + + offset: int + """Offset the number of browser pools to return.""" diff --git a/src/kernel/types/browser_pool_list_response.py b/src/kernel/types/browser_pool_list_response.py deleted file mode 100644 index a11c4de2..00000000 --- a/src/kernel/types/browser_pool_list_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# 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/tests/api_resources/test_browser_pools.py b/tests/api_resources/test_browser_pools.py index 42f47e63..c71e6c27 100644 --- a/tests/api_resources/test_browser_pools.py +++ b/tests/api_resources/test_browser_pools.py @@ -11,9 +11,9 @@ from tests.utils import assert_matches_type from kernel.types import ( BrowserPool, - BrowserPoolListResponse, BrowserPoolAcquireResponse, ) +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -211,7 +211,16 @@ def test_path_params_update(self, client: Kernel) -> None: @parametrize def test_method_list(self, client: Kernel) -> None: browser_pool = client.browser_pools.list() - assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + browser_pool = client.browser_pools.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -221,7 +230,7 @@ def test_raw_response_list(self, client: Kernel) -> None: 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"]) + assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -231,7 +240,7 @@ def test_streaming_response_list(self, client: Kernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" browser_pool = response.parse() - assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + assert_matches_type(SyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) assert cast(Any, response.is_closed) is True @@ -631,7 +640,16 @@ async def test_path_params_update(self, async_client: AsyncKernel) -> None: @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"]) + assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + browser_pool = await async_client.browser_pools.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -641,7 +659,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None: 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"]) + assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -651,7 +669,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" browser_pool = await response.parse() - assert_matches_type(BrowserPoolListResponse, browser_pool, path=["response"]) + assert_matches_type(AsyncOffsetPagination[BrowserPool], browser_pool, path=["response"]) assert cast(Any, response.is_closed) is True From 55c332493f9c7efd21ef8a2fdae40c8318e704cb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:29:10 +0000 Subject: [PATCH 3/5] feat: api: paginate GET /extensions --- .stats.yml | 6 +- api.md | 2 +- src/kernel/resources/extensions.py | 83 +++++++++++++++++---- src/kernel/types/__init__.py | 1 + src/kernel/types/extension_list_params.py | 15 ++++ src/kernel/types/extension_list_response.py | 10 +-- tests/api_resources/test_extensions.py | 31 ++++++-- 7 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 src/kernel/types/extension_list_params.py diff --git a/.stats.yml b/.stats.yml index d6e38f27..582e6b44 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e5524e6eeeedc614c05bf19896f1ce6c4f8a113de85c02952d6874d579651f70.yml -openapi_spec_hash: 7815a189a50e6aa9e283213cc78d041c -config_hash: 453b25a35834fd59a55a2315d1d50746 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-9a76e7a837ac9ffbe0e9557d618ce9b676e052249e364e516c28ddb33b912019.yml +openapi_spec_hash: c0e5412cc95139f11a8b8635559bb985 +config_hash: 098a7f3fd134c8e4cbd3a44750892a18 diff --git a/api.md b/api.md index 8a6b8c6e..6001d530 100644 --- a/api.md +++ b/api.md @@ -338,7 +338,7 @@ from kernel.types import ExtensionListResponse, ExtensionUploadResponse Methods: -- client.extensions.list() -> ExtensionListResponse +- client.extensions.list(\*\*params) -> SyncOffsetPagination[ExtensionListResponse] - client.extensions.delete(id_or_name) -> None - client.extensions.download(id_or_name) -> BinaryAPIResponse - client.extensions.download_from_chrome_store(\*\*params) -> BinaryAPIResponse diff --git a/src/kernel/resources/extensions.py b/src/kernel/resources/extensions.py index d5cf0eb7..5b7215be 100644 --- a/src/kernel/resources/extensions.py +++ b/src/kernel/resources/extensions.py @@ -7,7 +7,7 @@ import httpx -from ..types import extension_upload_params, extension_download_from_chrome_store_params +from ..types import extension_list_params, extension_upload_params, extension_download_from_chrome_store_params from .._files import deepcopy_with_paths from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, FileTypes, omit, not_given from .._utils import extract_files, path_template, maybe_transform, async_maybe_transform @@ -27,7 +27,8 @@ async_to_custom_raw_response_wrapper, async_to_custom_streamed_response_wrapper, ) -from .._base_client import make_request_options +from ..pagination import SyncOffsetPagination, AsyncOffsetPagination +from .._base_client import AsyncPaginator, make_request_options from ..types.extension_list_response import ExtensionListResponse from ..types.extension_upload_response import ExtensionUploadResponse @@ -59,20 +60,48 @@ def with_streaming_response(self) -> ExtensionsResourceWithStreamingResponse: def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> ExtensionListResponse: - """List extensions owned by the caller's organization.""" - return self._get( + ) -> SyncOffsetPagination[ExtensionListResponse]: + """ + List extensions owned by the caller's organization. + + Args: + limit: Limit the number of extensions to return. + + offset: Offset the number of extensions to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/extensions", + page=SyncOffsetPagination[ExtensionListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + extension_list_params.ExtensionListParams, + ), ), - cast_to=ExtensionListResponse, + model=ExtensionListResponse, ) def delete( @@ -266,23 +295,51 @@ def with_streaming_response(self) -> AsyncExtensionsResourceWithStreamingRespons """ return AsyncExtensionsResourceWithStreamingResponse(self) - async def list( + def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> ExtensionListResponse: - """List extensions owned by the caller's organization.""" - return await self._get( + ) -> AsyncPaginator[ExtensionListResponse, AsyncOffsetPagination[ExtensionListResponse]]: + """ + List extensions owned by the caller's organization. + + Args: + limit: Limit the number of extensions to return. + + offset: Offset the number of extensions to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/extensions", + page=AsyncOffsetPagination[ExtensionListResponse], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + extension_list_params.ExtensionListParams, + ), ), - cast_to=ExtensionListResponse, + model=ExtensionListResponse, ) async def delete( diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index ae16742d..ef27f493 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -42,6 +42,7 @@ from .browser_curl_response import BrowserCurlResponse as BrowserCurlResponse from .browser_list_response import BrowserListResponse as BrowserListResponse from .browser_update_params import BrowserUpdateParams as BrowserUpdateParams +from .extension_list_params import ExtensionListParams as ExtensionListParams from .profile_create_params import ProfileCreateParams as ProfileCreateParams from .project_create_params import ProjectCreateParams as ProjectCreateParams from .project_update_params import ProjectUpdateParams as ProjectUpdateParams diff --git a/src/kernel/types/extension_list_params.py b/src/kernel/types/extension_list_params.py new file mode 100644 index 00000000..bccd61eb --- /dev/null +++ b/src/kernel/types/extension_list_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__ = ["ExtensionListParams"] + + +class ExtensionListParams(TypedDict, total=False): + limit: int + """Limit the number of extensions to return.""" + + offset: int + """Offset the number of extensions to return.""" diff --git a/src/kernel/types/extension_list_response.py b/src/kernel/types/extension_list_response.py index bf9e544d..6bb33561 100644 --- a/src/kernel/types/extension_list_response.py +++ b/src/kernel/types/extension_list_response.py @@ -1,15 +1,14 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import Optional from datetime import datetime -from typing_extensions import TypeAlias from .._models import BaseModel -__all__ = ["ExtensionListResponse", "ExtensionListResponseItem"] +__all__ = ["ExtensionListResponse"] -class ExtensionListResponseItem(BaseModel): +class ExtensionListResponse(BaseModel): """A browser extension uploaded to Kernel.""" id: str @@ -29,6 +28,3 @@ class ExtensionListResponseItem(BaseModel): Must be unique within the project. """ - - -ExtensionListResponse: TypeAlias = List[ExtensionListResponseItem] diff --git a/tests/api_resources/test_extensions.py b/tests/api_resources/test_extensions.py index 4a28fb5e..302ba958 100644 --- a/tests/api_resources/test_extensions.py +++ b/tests/api_resources/test_extensions.py @@ -21,6 +21,7 @@ StreamedBinaryAPIResponse, AsyncStreamedBinaryAPIResponse, ) +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -32,7 +33,16 @@ class TestExtensions: @parametrize def test_method_list(self, client: Kernel) -> None: extension = client.extensions.list() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + extension = client.extensions.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -42,7 +52,7 @@ def test_raw_response_list(self, client: Kernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" extension = response.parse() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -52,7 +62,7 @@ def test_streaming_response_list(self, client: Kernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" extension = response.parse() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(SyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) assert cast(Any, response.is_closed) is True @@ -256,7 +266,16 @@ class TestAsyncExtensions: @parametrize async def test_method_list(self, async_client: AsyncKernel) -> None: extension = await async_client.extensions.list() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + extension = await async_client.extensions.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -266,7 +285,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" extension = await response.parse() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -276,7 +295,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" extension = await response.parse() - assert_matches_type(ExtensionListResponse, extension, path=["response"]) + assert_matches_type(AsyncOffsetPagination[ExtensionListResponse], extension, path=["response"]) assert cast(Any, response.is_closed) is True From 01897bc9f7215580aa2f2ca41bfcf1b4d29e9005 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:04:06 +0000 Subject: [PATCH 4/5] feat: api: paginate GET /org/credential_providers --- .stats.yml | 6 +- api.md | 3 +- src/kernel/resources/credential_providers.py | 88 ++++++++++++++++--- src/kernel/types/__init__.py | 2 +- .../types/credential_provider_list_params.py | 15 ++++ .../credential_provider_list_response.py | 10 --- .../test_credential_providers.py | 32 +++++-- 7 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 src/kernel/types/credential_provider_list_params.py delete mode 100644 src/kernel/types/credential_provider_list_response.py diff --git a/.stats.yml b/.stats.yml index 582e6b44..5ea72073 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-9a76e7a837ac9ffbe0e9557d618ce9b676e052249e364e516c28ddb33b912019.yml -openapi_spec_hash: c0e5412cc95139f11a8b8635559bb985 -config_hash: 098a7f3fd134c8e4cbd3a44750892a18 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-e6c711f0d29a7d956cc8ca621440da966c1f1575b1205d01328b1099edf1c517.yml +openapi_spec_hash: c06e7e36de1c6f9b29b54a6e3dc08ee5 +config_hash: 36159c262d293fbeacf513ab600a1729 diff --git a/api.md b/api.md index 6001d530..8f9df345 100644 --- a/api.md +++ b/api.md @@ -441,7 +441,6 @@ from kernel.types import ( CredentialProviderItem, CredentialProviderTestResult, UpdateCredentialProviderRequest, - CredentialProviderListResponse, CredentialProviderListItemsResponse, ) ``` @@ -451,7 +450,7 @@ Methods: - client.credential_providers.create(\*\*params) -> CredentialProvider - client.credential_providers.retrieve(id) -> CredentialProvider - client.credential_providers.update(id, \*\*params) -> CredentialProvider -- client.credential_providers.list() -> CredentialProviderListResponse +- client.credential_providers.list(\*\*params) -> SyncOffsetPagination[CredentialProvider] - client.credential_providers.delete(id) -> None - client.credential_providers.list_items(id) -> CredentialProviderListItemsResponse - client.credential_providers.test(id) -> CredentialProviderTestResult diff --git a/src/kernel/resources/credential_providers.py b/src/kernel/resources/credential_providers.py index 2dede2c4..06bf2aee 100644 --- a/src/kernel/resources/credential_providers.py +++ b/src/kernel/resources/credential_providers.py @@ -6,7 +6,11 @@ import httpx -from ..types import credential_provider_create_params, credential_provider_update_params +from ..types import ( + credential_provider_list_params, + credential_provider_create_params, + credential_provider_update_params, +) from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property @@ -17,10 +21,10 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from .._base_client import make_request_options +from ..pagination import SyncOffsetPagination, AsyncOffsetPagination +from .._base_client import AsyncPaginator, make_request_options from ..types.credential_provider import CredentialProvider from ..types.credential_provider_test_result import CredentialProviderTestResult -from ..types.credential_provider_list_response import CredentialProviderListResponse from ..types.credential_provider_list_items_response import CredentialProviderListItemsResponse __all__ = ["CredentialProvidersResource", "AsyncCredentialProvidersResource"] @@ -194,20 +198,48 @@ def update( def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> CredentialProviderListResponse: - """List external credential providers configured for the organization.""" - return self._get( + ) -> SyncOffsetPagination[CredentialProvider]: + """ + List external credential providers configured for the organization. + + Args: + limit: Limit the number of credential providers to return. + + offset: Offset the number of credential providers to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/org/credential_providers", + page=SyncOffsetPagination[CredentialProvider], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + credential_provider_list_params.CredentialProviderListParams, + ), ), - cast_to=CredentialProviderListResponse, + model=CredentialProvider, ) def delete( @@ -477,23 +509,51 @@ async def update( cast_to=CredentialProvider, ) - async def list( + def list( self, *, + limit: int | Omit = omit, + offset: 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, - ) -> CredentialProviderListResponse: - """List external credential providers configured for the organization.""" - return await self._get( + ) -> AsyncPaginator[CredentialProvider, AsyncOffsetPagination[CredentialProvider]]: + """ + List external credential providers configured for the organization. + + Args: + limit: Limit the number of credential providers to return. + + offset: Offset the number of credential providers to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( "/org/credential_providers", + page=AsyncOffsetPagination[CredentialProvider], options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + credential_provider_list_params.CredentialProviderListParams, + ), ), - cast_to=CredentialProviderListResponse, + model=CredentialProvider, ) async def delete( diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index ef27f493..7932162d 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -86,9 +86,9 @@ from .browser_pool_acquire_response import BrowserPoolAcquireResponse as BrowserPoolAcquireResponse from .credential_totp_code_response import CredentialTotpCodeResponse as CredentialTotpCodeResponse from .browser_load_extensions_params import BrowserLoadExtensionsParams as BrowserLoadExtensionsParams +from .credential_provider_list_params import CredentialProviderListParams as CredentialProviderListParams from .credential_provider_test_result import CredentialProviderTestResult as CredentialProviderTestResult from .credential_provider_create_params import CredentialProviderCreateParams as CredentialProviderCreateParams -from .credential_provider_list_response import CredentialProviderListResponse as CredentialProviderListResponse from .credential_provider_update_params import CredentialProviderUpdateParams as CredentialProviderUpdateParams from .invocation_list_browsers_response import InvocationListBrowsersResponse as InvocationListBrowsersResponse from .credential_provider_list_items_response import ( diff --git a/src/kernel/types/credential_provider_list_params.py b/src/kernel/types/credential_provider_list_params.py new file mode 100644 index 00000000..87dbfd69 --- /dev/null +++ b/src/kernel/types/credential_provider_list_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__ = ["CredentialProviderListParams"] + + +class CredentialProviderListParams(TypedDict, total=False): + limit: int + """Limit the number of credential providers to return.""" + + offset: int + """Offset the number of credential providers to return.""" diff --git a/src/kernel/types/credential_provider_list_response.py b/src/kernel/types/credential_provider_list_response.py deleted file mode 100644 index 59814e03..00000000 --- a/src/kernel/types/credential_provider_list_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import TypeAlias - -from .credential_provider import CredentialProvider - -__all__ = ["CredentialProviderListResponse"] - -CredentialProviderListResponse: TypeAlias = List[CredentialProvider] diff --git a/tests/api_resources/test_credential_providers.py b/tests/api_resources/test_credential_providers.py index 93f44145..d9795332 100644 --- a/tests/api_resources/test_credential_providers.py +++ b/tests/api_resources/test_credential_providers.py @@ -12,9 +12,9 @@ from kernel.types import ( CredentialProvider, CredentialProviderTestResult, - CredentialProviderListResponse, CredentialProviderListItemsResponse, ) +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -174,7 +174,16 @@ def test_path_params_update(self, client: Kernel) -> None: @parametrize def test_method_list(self, client: Kernel) -> None: credential_provider = client.credential_providers.list() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + credential_provider = client.credential_providers.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -184,7 +193,7 @@ def test_raw_response_list(self, client: Kernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" credential_provider = response.parse() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -194,7 +203,7 @@ def test_streaming_response_list(self, client: Kernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" credential_provider = response.parse() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(SyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) assert cast(Any, response.is_closed) is True @@ -482,7 +491,16 @@ async def test_path_params_update(self, async_client: AsyncKernel) -> None: @parametrize async def test_method_list(self, async_client: AsyncKernel) -> None: credential_provider = await async_client.credential_providers.list() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + credential_provider = await async_client.credential_providers.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -492,7 +510,7 @@ async def test_raw_response_list(self, async_client: AsyncKernel) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" credential_provider = await response.parse() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -502,7 +520,7 @@ async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" credential_provider = await response.parse() - assert_matches_type(CredentialProviderListResponse, credential_provider, path=["response"]) + assert_matches_type(AsyncOffsetPagination[CredentialProvider], credential_provider, path=["response"]) assert cast(Any, response.is_closed) is True From 14e4b34cd4dfaf19da62c4826a4efeefcc86b4f4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:04:39 +0000 Subject: [PATCH 5/5] release: 0.62.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f7e971ea..fdce8724 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.61.0" + ".": "0.62.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fbffa57e..bbd58123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 0.62.0 (2026-06-04) + +Full Changelog: [v0.61.0...v0.62.0](https://github.com/kernel/kernel-python-sdk/compare/v0.61.0...v0.62.0) + +### Features + +* api: paginate GET /browser_pools ([c25d693](https://github.com/kernel/kernel-python-sdk/commit/c25d693e310a1035d74654018f68b311f37545d0)) +* api: paginate GET /extensions ([55c3324](https://github.com/kernel/kernel-python-sdk/commit/55c332493f9c7efd21ef8a2fdae40c8318e704cb)) +* api: paginate GET /org/credential_providers ([01897bc](https://github.com/kernel/kernel-python-sdk/commit/01897bc9f7215580aa2f2ca41bfcf1b4d29e9005)) +* api: paginate GET /proxies ([7ff0bdf](https://github.com/kernel/kernel-python-sdk/commit/7ff0bdf181029f0711b694fb6498fbc75183b0f3)) + ## 0.61.0 (2026-06-03) Full Changelog: [v0.60.0...v0.61.0](https://github.com/kernel/kernel-python-sdk/compare/v0.60.0...v0.61.0) diff --git a/pyproject.toml b/pyproject.toml index 2b9342ba..f246f34a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.61.0" +version = "0.62.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index fc502359..785c4450 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.61.0" # x-release-please-version +__version__ = "0.62.0" # x-release-please-version