Skip to content

Commit 80e662a

Browse files
release: 1.2.0 (#704)
* chore: update uv.lock * fix: ensure streams are always closed * chore(deps): mypy 1.18.1 has a regression, pin to 1.17 * chore(internal): version bump * chore: bump required `uv` version * chore: update lockfile * chore(docs): use environment variables for authentication in code snippets * feat(devbox): return user for createSshKey * feat(devbox): default to x86 arch * release: 1.2.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent a2d5326 commit 80e662a

27 files changed

Lines changed: 273 additions & 369 deletions

.github/workflows/publish-pypi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Install uv
2020
uses: runloopai/setup-uv@main
2121
with:
22-
version: '0.8.11'
22+
version: '0.9.13'
2323

2424
- name: Publish to PyPI
2525
run: |

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.1.0"
2+
".": "1.2.0"
33
}

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 97
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-cb2d725f71e87810cd872eacd70e867ca10f94980fdf9c78bb2844c02ee47bf3.yml
3-
openapi_spec_hash: 16ce3e9184fc2afdee66db18a83a96e8
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-f2df3524e4b99c38b634c334d098aa2c7d543d5ea0f49c4dd8f4d92723b81b94.yml
3+
openapi_spec_hash: c377abec5716d1d6c5b01a527a5bfdfb
44
config_hash: 2363f563f42501d2b1587a4f64bdccaf

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Changelog
22

3+
## 1.2.0 (2025-12-09)
4+
5+
Full Changelog: [v1.1.0...v1.2.0](https://github.com/runloopai/api-client-python/compare/v1.1.0...v1.2.0)
6+
7+
### Features
8+
9+
* **devbox:** default to x86 arch ([501de0b](https://github.com/runloopai/api-client-python/commit/501de0bb1d76c836ff9f448513a16155641345ae))
10+
* **devbox:** return user for createSshKey ([f094bf7](https://github.com/runloopai/api-client-python/commit/f094bf7443a0ca5bab6d47a53b7b14bade3cecd0))
11+
12+
13+
### Bug Fixes
14+
15+
* ensure streams are always closed ([d01aae2](https://github.com/runloopai/api-client-python/commit/d01aae204d8c57ac76646df0e0e1078e64ad9891))
16+
17+
18+
### Chores
19+
20+
* bump required `uv` version ([8ad519f](https://github.com/runloopai/api-client-python/commit/8ad519fd26d389628d157a413a0b0f1f5d435e9e))
21+
* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([e56582a](https://github.com/runloopai/api-client-python/commit/e56582a93590445d8e545b6123be0f14db39a8f5))
22+
* **docs:** use environment variables for authentication in code snippets ([55cf613](https://github.com/runloopai/api-client-python/commit/55cf6131edb8d38144761c5dbbbcf9389093ed7b))
23+
* **internal:** version bump ([2fa85c6](https://github.com/runloopai/api-client-python/commit/2fa85c6694dc468280eedb28136aadcda4f11801))
24+
* remove some unnecessary changes to reduce diff from Stainless ([#705](https://github.com/runloopai/api-client-python/issues/705)) ([715c9d0](https://github.com/runloopai/api-client-python/commit/715c9d09f4e874032ee1d4d6c81d80ab6a72ec45))
25+
* update lockfile ([7e0136d](https://github.com/runloopai/api-client-python/commit/7e0136dfcd62a2843138ae382bd6fedfd881e1b3))
26+
* update requirements-dev.lock ([#707](https://github.com/runloopai/api-client-python/issues/707)) ([a2d5326](https://github.com/runloopai/api-client-python/commit/a2d5326634cad5afe6c74252d26b01916ed41bcb))
27+
* update uv.lock ([b9e0729](https://github.com/runloopai/api-client-python/commit/b9e07291745291d16f122dbca5ef513ed134c5dd))
28+
329
## 1.1.0 (2025-12-06)
430

531
Full Changelog: [v1.0.0...v1.1.0](https://github.com/runloopai/api-client-python/compare/v1.0.0...v1.1.0)

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,15 @@ pip install runloop_api_client[aiohttp]
102102
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
103103

104104
```python
105+
import os
105106
import asyncio
106107
from runloop_api_client import DefaultAioHttpClient
107108
from runloop_api_client import AsyncRunloop
108109

109110

110111
async def main() -> None:
111112
async with AsyncRunloop(
112-
bearer_token="My Bearer Token",
113+
bearer_token=os.environ.get("RUNLOOP_API_KEY"), # This is the default and can be omitted
113114
http_client=DefaultAioHttpClient(),
114115
) as client:
115116
devbox_view = await client.devboxes.create()

api.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
```python
44
from runloop_api_client.types import (
55
AfterIdle,
6-
AgentMountParameters,
76
AgentSource,
87
CodeMountParameters,
98
LaunchParameters,
109
Mount,
11-
ObjectMountParameters,
1210
RunProfile,
1311
)
1412
```

pyproject.toml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
[project]
22
name = "runloop_api_client"
3-
version = "1.1.0"
3+
version = "1.2.0"
44
description = "The official Python library for the runloop API"
55
dynamic = ["readme"]
66
license = "MIT"
77
authors = [
88
{ name = "Runloop", email = "support@runloop.ai" },
99
]
10+
1011
dependencies = [
11-
"httpx>=0.23.0, <1",
12-
"pydantic>=1.9.0, <3",
13-
"typing-extensions>=4.10, <5",
14-
"anyio>=3.5.0, <5",
15-
"distro>=1.7.0, <2",
16-
"sniffio",
12+
"httpx>=0.23.0, <1",
13+
"pydantic>=1.9.0, <3",
14+
"typing-extensions>=4.10, <5",
15+
"anyio>=3.5.0, <5",
16+
"distro>=1.7.0, <2",
17+
"sniffio",
1718
"uuid-utils>=0.11.0",
1819
]
20+
1921
requires-python = ">= 3.9"
2022
classifiers = [
2123
"Typing :: Typed",
@@ -56,7 +58,7 @@ conflicts = [
5658
# version pins are in uv.lock
5759
dev = [
5860
"pyright==1.1.399",
59-
"mypy",
61+
"mypy==1.17",
6062
"respx",
6163
"pytest",
6264
"pytest-asyncio",

requirements-dev.lock

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ certifi==2025.11.12
1515
# httpx
1616
colorama==0.4.6 ; sys_platform == 'win32'
1717
# via pytest
18-
coverage==7.10.7 ; python_full_version < '3.10'
19-
# via pytest-cov
20-
coverage==7.13.0 ; python_full_version >= '3.10'
21-
# via pytest-cov
2218
dirty-equals==0.11
2319
distro==1.9.0
2420
# via runloop-api-client
@@ -45,15 +41,13 @@ iniconfig==2.1.0 ; python_full_version < '3.10'
4541
# via pytest
4642
iniconfig==2.3.0 ; python_full_version >= '3.10'
4743
# via pytest
48-
librt==0.7.3
49-
# via mypy
5044
markdown-it-py==3.0.0 ; python_full_version < '3.10'
5145
# via rich
5246
markdown-it-py==4.0.0 ; python_full_version >= '3.10'
5347
# via rich
5448
mdurl==0.1.2
5549
# via markdown-it-py
56-
mypy==1.19.0
50+
mypy==1.17.0
5751
mypy-extensions==1.1.0
5852
# via mypy
5953
nodeenv==1.9.1
@@ -63,9 +57,7 @@ packaging==25.0
6357
pathspec==0.12.1
6458
# via mypy
6559
pluggy==1.6.0
66-
# via
67-
# pytest
68-
# pytest-cov
60+
# via pytest
6961
pydantic==2.12.5
7062
# via runloop-api-client
7163
pydantic-core==2.41.5
@@ -78,34 +70,27 @@ pyright==1.1.399
7870
pytest==8.4.2 ; python_full_version < '3.10'
7971
# via
8072
# pytest-asyncio
81-
# pytest-cov
82-
# pytest-timeout
8373
# pytest-xdist
84-
pytest==9.0.2 ; python_full_version >= '3.10'
74+
pytest==9.0.1 ; python_full_version >= '3.10'
8575
# via
8676
# pytest-asyncio
87-
# pytest-cov
88-
# pytest-timeout
8977
# pytest-xdist
9078
pytest-asyncio==1.2.0 ; python_full_version < '3.10'
9179
pytest-asyncio==1.3.0 ; python_full_version >= '3.10'
92-
pytest-cov==7.0.0
93-
pytest-timeout==2.4.0
9480
pytest-xdist==3.8.0
9581
python-dateutil==2.9.0.post0 ; python_full_version < '3.10'
9682
# via time-machine
9783
respx==0.22.0
9884
rich==14.2.0
99-
ruff==0.14.8
85+
ruff==0.14.7
10086
six==1.17.0 ; python_full_version < '3.10'
10187
# via python-dateutil
10288
sniffio==1.3.1
10389
# via runloop-api-client
10490
time-machine==2.19.0 ; python_full_version < '3.10'
10591
time-machine==3.1.0 ; python_full_version >= '3.10'
106-
tomli==2.3.0 ; python_full_version <= '3.11'
92+
tomli==2.3.0 ; python_full_version < '3.11'
10793
# via
108-
# coverage
10994
# mypy
11095
# pytest
11196
typing-extensions==4.15.0
@@ -121,7 +106,5 @@ typing-extensions==4.15.0
121106
# typing-inspection
122107
typing-inspection==0.4.2
123108
# via pydantic
124-
uuid-utils==0.12.0
125-
# via runloop-api-client
126109
zipp==3.23.0
127110
# via importlib-metadata

src/runloop_api_client/_streaming.py

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,22 @@ def __stream__(self) -> Iterator[_T]:
7373
process_data = self._client._process_response_data
7474
iterator = self._iter_events()
7575

76-
for sse in iterator:
77-
# Surface server-sent error events as API errors to allow callers to handle/retry
78-
if sse.event == "error":
79-
try:
80-
error_obj = json.loads(sse.data)
81-
status_code = int(error_obj.get("code", 500))
82-
# Build a synthetic response to mirror normal error handling
83-
fake_resp = httpx.Response(status_code, request=response.request, content=sse.data)
84-
except Exception:
85-
fake_resp = httpx.Response(500, request=response.request, content=sse.data)
86-
raise self._client._make_status_error_from_response(fake_resp)
87-
88-
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
89-
90-
# As we might not fully consume the response stream, we need to close it explicitly
91-
response.close()
76+
try:
77+
for sse in iterator:
78+
# Surface server-sent error events as API errors to allow callers to handle/retry
79+
if sse.event == "error":
80+
try:
81+
error_obj = json.loads(sse.data)
82+
status_code = int(error_obj.get("code", 500))
83+
fake_resp = httpx.Response(status_code, request=response.request, content=sse.data)
84+
except Exception:
85+
fake_resp = httpx.Response(500, request=response.request, content=sse.data)
86+
raise self._client._make_status_error_from_response(fake_resp)
87+
88+
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
89+
finally:
90+
# Ensure the response is closed even if the consumer doesn't read all data
91+
response.close()
9292

9393
def __enter__(self) -> Self:
9494
return self
@@ -147,22 +147,22 @@ async def __stream__(self) -> AsyncIterator[_T]:
147147
process_data = self._client._process_response_data
148148
iterator = self._iter_events()
149149

150-
async for sse in iterator:
151-
# Surface server-sent error events as API errors to allow callers to handle/retry
152-
if sse.event == "error":
153-
try:
154-
error_obj = json.loads(sse.data)
155-
status_code = int(error_obj.get("code", 500))
156-
# Build a synthetic response to mirror normal error handling
157-
fake_resp = httpx.Response(status_code, request=response.request, content=sse.data)
158-
except Exception:
159-
fake_resp = httpx.Response(500, request=response.request, content=sse.data)
160-
raise self._client._make_status_error_from_response(fake_resp)
161-
162-
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
163-
164-
# As we might not fully consume the response stream, we need to close it explicitly
165-
await response.aclose()
150+
try:
151+
async for sse in iterator:
152+
# Surface server-sent error events as API errors to allow callers to handle/retry
153+
if sse.event == "error":
154+
try:
155+
error_obj = json.loads(sse.data)
156+
status_code = int(error_obj.get("code", 500))
157+
fake_resp = httpx.Response(status_code, request=response.request, content=sse.data)
158+
except Exception:
159+
fake_resp = httpx.Response(500, request=response.request, content=sse.data)
160+
raise self._client._make_status_error_from_response(fake_resp)
161+
162+
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
163+
finally:
164+
# Ensure the response is closed even if the consumer doesn't read all data
165+
await response.aclose()
166166

167167
async def __aenter__(self) -> Self:
168168
return self

src/runloop_api_client/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "runloop_api_client"
4-
__version__ = "1.1.0" # x-release-please-version
4+
__version__ = "1.2.0" # x-release-please-version

0 commit comments

Comments
 (0)