diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 554e34bbe..f81bf9923 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.30.0" + ".": "0.31.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index d1b99e300..a9ee988af 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 79 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-59d51521fb27127ec00a91d37d9cbaa484577dbd200d290e61c9d69d33b3c760.yml -openapi_spec_hash: 4ad68555fc0ec3e969817bebff620e88 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-29770148092f0f5030e7199308862afc7e46cb12da6081cd045e9db6734d3ac9.yml +openapi_spec_hash: b100a6769bf25a0f873ef32201eba45e config_hash: 4cb90c87fb61338e46c50cea9c42abd7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7750bbe2e..6eb0ff073 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 0.31.0 (2025-04-21) + +Full Changelog: [v0.30.0...v0.31.0](https://github.com/runloopai/api-client-python/compare/v0.30.0...v0.31.0) + +### Features + +* **api:** api update ([4c348b6](https://github.com/runloopai/api-client-python/commit/4c348b65cf8e0c59b1cc04122a2a53bc863e053b)) + + +### Chores + +* **internal:** base client updates ([71a0a00](https://github.com/runloopai/api-client-python/commit/71a0a00703668b365cce28979bf052d2c1ce78a9)) +* **internal:** bump pyright version ([950fe0d](https://github.com/runloopai/api-client-python/commit/950fe0d00ec77063e2a8b7dedba256e2878c41bb)) +* **internal:** update models test ([def3490](https://github.com/runloopai/api-client-python/commit/def3490573a3b1b304287b54e30cd26fd86dc1ac)) + ## 0.30.0 (2025-04-16) Full Changelog: [v0.29.0...v0.30.0](https://github.com/runloopai/api-client-python/compare/v0.29.0...v0.30.0) diff --git a/README.md b/README.md index 1e29f41fd..00c2c41bf 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ devbox_view = client.devboxes.create( "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, diff --git a/pyproject.toml b/pyproject.toml index d328c6824..6a30dc50f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "runloop_api_client" -version = "0.30.0" +version = "0.31.0" description = "The official Python library for the runloop API" dynamic = ["readme"] license = "MIT" @@ -42,7 +42,7 @@ Repository = "https://github.com/runloopai/api-client-python" managed = true # version pins are in requirements-dev.lock dev-dependencies = [ - "pyright>=1.1.359", + "pyright==1.1.399", "mypy", "respx", "pytest", diff --git a/requirements-dev.lock b/requirements-dev.lock index c88f710ae..1e04b71cc 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -69,7 +69,7 @@ pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich -pyright==1.1.392.post0 +pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio pytest-asyncio==0.24.0 diff --git a/src/runloop_api_client/_base_client.py b/src/runloop_api_client/_base_client.py index 7d2d646f9..32f743a59 100644 --- a/src/runloop_api_client/_base_client.py +++ b/src/runloop_api_client/_base_client.py @@ -98,7 +98,11 @@ _AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) if TYPE_CHECKING: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT + from httpx._config import ( + DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] + ) + + HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG else: try: from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT @@ -115,6 +119,7 @@ class PageInfo: url: URL | NotGiven params: Query | NotGiven + json: Body | NotGiven @overload def __init__( @@ -130,19 +135,30 @@ def __init__( params: Query, ) -> None: ... + @overload + def __init__( + self, + *, + json: Body, + ) -> None: ... + def __init__( self, *, url: URL | NotGiven = NOT_GIVEN, + json: Body | NotGiven = NOT_GIVEN, params: Query | NotGiven = NOT_GIVEN, ) -> None: self.url = url + self.json = json self.params = params @override def __repr__(self) -> str: if self.url: return f"{self.__class__.__name__}(url={self.url})" + if self.json: + return f"{self.__class__.__name__}(json={self.json})" return f"{self.__class__.__name__}(params={self.params})" @@ -191,6 +207,19 @@ def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: options.url = str(url) return options + if not isinstance(info.json, NotGiven): + if not is_mapping(info.json): + raise TypeError("Pagination is only supported with mappings") + + if not options.json_data: + options.json_data = {**info.json} + else: + if not is_mapping(options.json_data): + raise TypeError("Pagination is only supported with mappings") + + options.json_data = {**options.json_data, **info.json} + return options + raise ValueError("Unexpected PageInfo state") diff --git a/src/runloop_api_client/_models.py b/src/runloop_api_client/_models.py index 349357169..58b9263e8 100644 --- a/src/runloop_api_client/_models.py +++ b/src/runloop_api_client/_models.py @@ -19,7 +19,6 @@ ) import pydantic -import pydantic.generics from pydantic.fields import FieldInfo from ._types import ( diff --git a/src/runloop_api_client/_utils/_typing.py b/src/runloop_api_client/_utils/_typing.py index 1958820f8..1bac9542e 100644 --- a/src/runloop_api_client/_utils/_typing.py +++ b/src/runloop_api_client/_utils/_typing.py @@ -110,7 +110,7 @@ class MyResponse(Foo[_T]): ``` """ cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: + if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] # we're given the class directly return extract_type_arg(typ, index) diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py index 524beb9ff..8d021c0e2 100644 --- a/src/runloop_api_client/_version.py +++ b/src/runloop_api_client/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "runloop_api_client" -__version__ = "0.30.0" # x-release-please-version +__version__ = "0.31.0" # x-release-please-version diff --git a/src/runloop_api_client/types/shared/launch_parameters.py b/src/runloop_api_client/types/shared/launch_parameters.py index ce15b90b0..5d5fa1178 100644 --- a/src/runloop_api_client/types/shared/launch_parameters.py +++ b/src/runloop_api_client/types/shared/launch_parameters.py @@ -16,6 +16,9 @@ class LaunchParameters(BaseModel): If after_idle is set, Devbox will ignore keep_alive_time_seconds. """ + architecture: Optional[Literal["x86_64", "arm64"]] = None + """The target architecture for the Devbox. If unset, defaults to arm64.""" + available_ports: Optional[List[int]] = None """A list of ports to make available on the Devbox. diff --git a/src/runloop_api_client/types/shared_params/launch_parameters.py b/src/runloop_api_client/types/shared_params/launch_parameters.py index 76aa7393f..decfb9feb 100644 --- a/src/runloop_api_client/types/shared_params/launch_parameters.py +++ b/src/runloop_api_client/types/shared_params/launch_parameters.py @@ -17,6 +17,9 @@ class LaunchParameters(TypedDict, total=False): If after_idle is set, Devbox will ignore keep_alive_time_seconds. """ + architecture: Optional[Literal["x86_64", "arm64"]] + """The target architecture for the Devbox. If unset, defaults to arm64.""" + available_ports: Optional[Iterable[int]] """A list of ports to make available on the Devbox. diff --git a/tests/api_resources/scenarios/test_scorers.py b/tests/api_resources/scenarios/test_scorers.py index 0ac377ede..05ec020d4 100644 --- a/tests/api_resources/scenarios/test_scorers.py +++ b/tests/api_resources/scenarios/test_scorers.py @@ -195,6 +195,7 @@ def test_method_validate_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -418,6 +419,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncRunloop) "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, diff --git a/tests/api_resources/test_blueprints.py b/tests/api_resources/test_blueprints.py index 5e33440e5..be38be581 100644 --- a/tests/api_resources/test_blueprints.py +++ b/tests/api_resources/test_blueprints.py @@ -48,6 +48,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -257,6 +258,7 @@ def test_method_preview_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -322,6 +324,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -531,6 +534,7 @@ async def test_method_preview_with_all_params(self, async_client: AsyncRunloop) "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py index b0bf4b4a5..b0b96d7a4 100644 --- a/tests/api_resources/test_devboxes.py +++ b/tests/api_resources/test_devboxes.py @@ -64,6 +64,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -939,6 +940,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, diff --git a/tests/api_resources/test_scenarios.py b/tests/api_resources/test_scenarios.py index 2d6d7048f..73af952a4 100644 --- a/tests/api_resources/test_scenarios.py +++ b/tests/api_resources/test_scenarios.py @@ -77,6 +77,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -239,6 +240,7 @@ def test_method_update_with_all_params(self, client: Runloop) -> None: "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -499,6 +501,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, @@ -661,6 +664,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncRunloop) - "idle_time_seconds": 0, "on_idle": "shutdown", }, + "architecture": "x86_64", "available_ports": [0], "custom_cpu_cores": 0, "custom_gb_memory": 0, diff --git a/tests/conftest.py b/tests/conftest.py index 60d391097..fe6961d03 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ from runloop_api_client import Runloop, AsyncRunloop if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest + from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] pytest.register_assert_rewrite("tests.utils") diff --git a/tests/test_models.py b/tests/test_models.py index b65dd474e..e47644414 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -492,12 +492,15 @@ class Model(BaseModel): resource_id: Optional[str] = None m = Model.construct() + assert m.resource_id is None assert "resource_id" not in m.model_fields_set m = Model.construct(resource_id=None) + assert m.resource_id is None assert "resource_id" in m.model_fields_set m = Model.construct(resource_id="foo") + assert m.resource_id == "foo" assert "resource_id" in m.model_fields_set @@ -832,7 +835,7 @@ class B(BaseModel): @pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: - Alias = TypeAliasType("Alias", str) + Alias = TypeAliasType("Alias", str) # pyright: ignore class Model(BaseModel): alias: Alias