From 8bceece9fb86d9dbc0446abd1018788ff4fbda80 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 10 May 2025 19:20:26 +0000 Subject: [PATCH 1/2] feat(api): update via SDK Studio --- .stats.yml | 2 +- README.md | 4 ++ src/kernel/__init__.py | 14 ++++++- src/kernel/_client.py | 93 ++++++++++++++++++++++++++++++++++++------ tests/test_client.py | 18 ++++++++ 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3b0a5f2..1a7891f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 4 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-d168b58fcf39dbd0458d132091793d3e2d0930070b7dda2d5f7f1baff20dd31b.yml openapi_spec_hash: b7e0fd7ee1656d7dbad57209d1584d92 -config_hash: c2bc5253d8afd6d67e031f73353c9b22 +config_hash: 2d282609080a6011e3f6222451f72237 diff --git a/README.md b/README.md index 0e3afec..ab4e765 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ from kernel import Kernel client = Kernel( api_key=os.environ.get("KERNEL_API_KEY"), # This is the default and can be omitted + # defaults to "production". + environment="development", ) response = client.apps.deploy( @@ -55,6 +57,8 @@ from kernel import AsyncKernel client = AsyncKernel( api_key=os.environ.get("KERNEL_API_KEY"), # This is the default and can be omitted + # defaults to "production". + environment="development", ) diff --git a/src/kernel/__init__.py b/src/kernel/__init__.py index e9960a8..8bc4875 100644 --- a/src/kernel/__init__.py +++ b/src/kernel/__init__.py @@ -5,7 +5,18 @@ from . import types from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path -from ._client import Client, Kernel, Stream, Timeout, Transport, AsyncClient, AsyncKernel, AsyncStream, RequestOptions +from ._client import ( + ENVIRONMENTS, + Client, + Kernel, + Stream, + Timeout, + Transport, + AsyncClient, + AsyncKernel, + AsyncStream, + RequestOptions, +) from ._models import BaseModel from ._version import __title__, __version__ from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse @@ -73,6 +84,7 @@ "AsyncStream", "Kernel", "AsyncKernel", + "ENVIRONMENTS", "file_from_path", "BaseModel", "DEFAULT_TIMEOUT", diff --git a/src/kernel/_client.py b/src/kernel/_client.py index aa9f227..28871ba 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -3,8 +3,8 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping -from typing_extensions import Self, override +from typing import Any, Dict, Union, Mapping, cast +from typing_extensions import Self, Literal, override import httpx @@ -30,7 +30,22 @@ AsyncAPIClient, ) -__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Kernel", "AsyncKernel", "Client", "AsyncClient"] +__all__ = [ + "ENVIRONMENTS", + "Timeout", + "Transport", + "ProxiesTypes", + "RequestOptions", + "Kernel", + "AsyncKernel", + "Client", + "AsyncClient", +] + +ENVIRONMENTS: Dict[str, str] = { + "production": "https://api.onkernel.com/", + "development": "https://localhost:3001/", +} class Kernel(SyncAPIClient): @@ -42,11 +57,14 @@ class Kernel(SyncAPIClient): # client options api_key: str + _environment: Literal["production", "development"] | NotGiven + def __init__( self, *, api_key: str | None = None, - base_url: str | httpx.URL | None = None, + environment: Literal["production", "development"] | NotGiven = NOT_GIVEN, + base_url: str | httpx.URL | None | NotGiven = NOT_GIVEN, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -77,10 +95,31 @@ def __init__( ) self.api_key = api_key - if base_url is None: - base_url = os.environ.get("KERNEL_BASE_URL") - if base_url is None: - base_url = f"http://localhost:3001" + self._environment = environment + + base_url_env = os.environ.get("KERNEL_BASE_URL") + if is_given(base_url) and base_url is not None: + # cast required because mypy doesn't understand the type narrowing + base_url = cast("str | httpx.URL", base_url) # pyright: ignore[reportUnnecessaryCast] + elif is_given(environment): + if base_url_env and base_url is not None: + raise ValueError( + "Ambiguous URL; The `KERNEL_BASE_URL` env var and the `environment` argument are given. If you want to use the environment, you must pass base_url=None", + ) + + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + elif base_url_env is not None: + base_url = base_url_env + else: + self._environment = environment = "production" + + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc super().__init__( version=__version__, @@ -122,6 +161,7 @@ def copy( self, *, api_key: str | None = None, + environment: Literal["production", "development"] | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.Client | None = None, @@ -157,6 +197,7 @@ def copy( return self.__class__( api_key=api_key or self.api_key, base_url=base_url or self.base_url, + environment=environment or self._environment, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, max_retries=max_retries if is_given(max_retries) else self.max_retries, @@ -212,11 +253,14 @@ class AsyncKernel(AsyncAPIClient): # client options api_key: str + _environment: Literal["production", "development"] | NotGiven + def __init__( self, *, api_key: str | None = None, - base_url: str | httpx.URL | None = None, + environment: Literal["production", "development"] | NotGiven = NOT_GIVEN, + base_url: str | httpx.URL | None | NotGiven = NOT_GIVEN, timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -247,10 +291,31 @@ def __init__( ) self.api_key = api_key - if base_url is None: - base_url = os.environ.get("KERNEL_BASE_URL") - if base_url is None: - base_url = f"http://localhost:3001" + self._environment = environment + + base_url_env = os.environ.get("KERNEL_BASE_URL") + if is_given(base_url) and base_url is not None: + # cast required because mypy doesn't understand the type narrowing + base_url = cast("str | httpx.URL", base_url) # pyright: ignore[reportUnnecessaryCast] + elif is_given(environment): + if base_url_env and base_url is not None: + raise ValueError( + "Ambiguous URL; The `KERNEL_BASE_URL` env var and the `environment` argument are given. If you want to use the environment, you must pass base_url=None", + ) + + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc + elif base_url_env is not None: + base_url = base_url_env + else: + self._environment = environment = "production" + + try: + base_url = ENVIRONMENTS[environment] + except KeyError as exc: + raise ValueError(f"Unknown environment: {environment}") from exc super().__init__( version=__version__, @@ -292,6 +357,7 @@ def copy( self, *, api_key: str | None = None, + environment: Literal["production", "development"] | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = NOT_GIVEN, http_client: httpx.AsyncClient | None = None, @@ -327,6 +393,7 @@ def copy( return self.__class__( api_key=api_key or self.api_key, base_url=base_url or self.base_url, + environment=environment or self._environment, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, max_retries=max_retries if is_given(max_retries) else self.max_retries, diff --git a/tests/test_client.py b/tests/test_client.py index c3540e3..75dabc6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -553,6 +553,14 @@ def test_base_url_env(self) -> None: client = Kernel(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" + # explicit environment arg requires explicitness + with update_env(KERNEL_BASE_URL="http://localhost:5000/from/env"): + with pytest.raises(ValueError, match=r"you must pass base_url=None"): + Kernel(api_key=api_key, _strict_response_validation=True, environment="production") + + client = Kernel(base_url=None, api_key=api_key, _strict_response_validation=True, environment="production") + assert str(client.base_url).startswith("https://api.onkernel.com/") + @pytest.mark.parametrize( "client", [ @@ -1341,6 +1349,16 @@ def test_base_url_env(self) -> None: client = AsyncKernel(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" + # explicit environment arg requires explicitness + with update_env(KERNEL_BASE_URL="http://localhost:5000/from/env"): + with pytest.raises(ValueError, match=r"you must pass base_url=None"): + AsyncKernel(api_key=api_key, _strict_response_validation=True, environment="production") + + client = AsyncKernel( + base_url=None, api_key=api_key, _strict_response_validation=True, environment="production" + ) + assert str(client.base_url).startswith("https://api.onkernel.com/") + @pytest.mark.parametrize( "client", [ From 83bb471f70cf90ca22a651f4a3d02e37dcd7e282 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 10 May 2025 19:20:40 +0000 Subject: [PATCH 2/2] release: 0.1.0-alpha.5 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b56c3d0..e8285b7 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.4" + ".": "0.1.0-alpha.5" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index a709e5d..3a60606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.0-alpha.5 (2025-05-10) + +Full Changelog: [v0.1.0-alpha.4...v0.1.0-alpha.5](https://github.com/onkernel/kernel-python-sdk/compare/v0.1.0-alpha.4...v0.1.0-alpha.5) + +### Features + +* **api:** update via SDK Studio ([8bceece](https://github.com/onkernel/kernel-python-sdk/commit/8bceece9fb86d9dbc0446abd1018788ff4fbda80)) + ## 0.1.0-alpha.4 (2025-05-10) Full Changelog: [v0.1.0-alpha.3...v0.1.0-alpha.4](https://github.com/onkernel/kernel-python-sdk/compare/v0.1.0-alpha.3...v0.1.0-alpha.4) diff --git a/pyproject.toml b/pyproject.toml index 8764ccd..1bca88c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.1.0-alpha.4" +version = "0.1.0-alpha.5" 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 f5e8430..55b53c6 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.1.0-alpha.4" # x-release-please-version +__version__ = "0.1.0-alpha.5" # x-release-please-version