Skip to content

Commit c7715c7

Browse files
release: 0.67.0 (#658)
* fix(client): close streams without requiring full consumption * chore(internal/tests): avoid race condition with implicit client cleanup * chore(internal): grammar fix (it's -> its) * feat(api): api update * codegen metadata * feat(blueprint): adds queued state * chore(package): drop Python 3.8 support * release: 0.67.0 --------- Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com>
1 parent a8c6138 commit c7715c7

19 files changed

Lines changed: 373 additions & 384 deletions

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.66.1"
2+
".": "0.67.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: 94
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-f60ee2123156a4db87ddfa4e1b8dd6379e26e8f8cf533946ca25b76559b6aa4d.yml
3-
openapi_spec_hash: d80fdfaf40c65ce8c1962c4f6d35acc6
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-91cec4aeec2421487d5eeece4804ae3b8b47e22bdbb9fc7460feb64a8c10e42f.yml
3+
openapi_spec_hash: 3d8d782e2450d46b8ce6573bad488ea1
44
config_hash: 95facb8cef59b5a1b05763b871bf6a4b

CHANGELOG.md

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

3+
## 0.67.0 (2025-11-14)
4+
5+
Full Changelog: [v0.66.1...v0.67.0](https://github.com/runloopai/api-client-python/compare/v0.66.1...v0.67.0)
6+
7+
### Features
8+
9+
* **api:** api update ([516c20b](https://github.com/runloopai/api-client-python/commit/516c20b3095d7e75b0e15647621bf92e0d79f5f4))
10+
* **blueprint:** adds queued state ([5893559](https://github.com/runloopai/api-client-python/commit/5893559e8839260876947d31f1090dd343f1cf43))
11+
12+
13+
### Bug Fixes
14+
15+
* **client:** close streams without requiring full consumption ([30f9ee5](https://github.com/runloopai/api-client-python/commit/30f9ee5b6cc5f42ce642b918c4e0194a4ab8bc7a))
16+
17+
18+
### Chores
19+
20+
* **internal/tests:** avoid race condition with implicit client cleanup ([7152280](https://github.com/runloopai/api-client-python/commit/71522809d211f5bbad89be807559ca2de591729f))
21+
* **internal:** grammar fix (it's -&gt; its) ([fd6963f](https://github.com/runloopai/api-client-python/commit/fd6963f1777dedc2db5b86dc222a5e70521134ba))
22+
* **package:** drop Python 3.8 support ([5026669](https://github.com/runloopai/api-client-python/commit/50266693caae9b3c6e6506cb58f096f1d439dcd0))
23+
324
## 0.66.1 (2025-10-23)
425

526
Full Changelog: [v0.66.0...v0.66.1](https://github.com/runloopai/api-client-python/compare/v0.66.0...v0.66.1)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<!-- prettier-ignore -->
44
[![PyPI version](https://img.shields.io/pypi/v/runloop_api_client.svg?label=pypi%20(stable))](https://pypi.org/project/runloop_api_client/)
55

6-
The Runloop Python library provides convenient access to the Runloop REST API from any Python 3.8+
6+
The Runloop Python library provides convenient access to the Runloop REST API from any Python 3.9+
77
application. The library includes type definitions for all request params and response fields,
88
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).
99

@@ -456,7 +456,7 @@ print(runloop_api_client.__version__)
456456

457457
## Requirements
458458

459-
Python 3.8 or higher.
459+
Python 3.9 or higher.
460460

461461
## Contributing
462462

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "runloop_api_client"
3-
version = "0.66.1"
3+
version = "0.67.0"
44
description = "The official Python library for the runloop API"
55
dynamic = ["readme"]
66
license = "MIT"

requirements-dev.lock

Lines changed: 11 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
-e .
44
annotated-types==0.7.0
55
# via pydantic
6-
anyio==4.5.2 ; python_full_version < '3.9'
7-
# via
8-
# httpx
9-
# runloop-api-client
10-
anyio==4.8.0 ; python_full_version >= '3.9'
6+
anyio==4.8.0
117
# via
128
# httpx
139
# runloop-api-client
@@ -38,8 +34,7 @@ idna==3.10
3834
# via
3935
# anyio
4036
# httpx
41-
importlib-metadata==8.5.0 ; python_full_version < '3.9'
42-
importlib-metadata==8.6.1 ; python_full_version >= '3.9'
37+
importlib-metadata==8.6.1
4338
iniconfig==2.0.0
4439
# via pytest
4540
markdown-it-py==3.0.0
@@ -55,30 +50,23 @@ packaging==24.2
5550
# via pytest
5651
pluggy==1.5.0
5752
# via pytest
58-
pydantic==2.10.6 ; python_full_version < '3.9'
53+
pydantic==2.10.3
5954
# via runloop-api-client
60-
pydantic==2.11.9 ; python_full_version >= '3.9'
61-
# via runloop-api-client
62-
pydantic-core==2.27.2 ; python_full_version < '3.9'
63-
# via pydantic
64-
pydantic-core==2.33.2 ; python_full_version >= '3.9'
55+
pydantic-core==2.27.1
6556
# via pydantic
6657
pygments==2.19.1
6758
# via
6859
# pytest
6960
# rich
7061
pyright==1.1.399
71-
pytest==8.3.3
72-
# via pytest-asyncio
73-
# via pytest-timeout
74-
# via pytest-xdist
62+
pytest==8.4.1
63+
# via
64+
# pytest-asyncio
65+
# pytest-xdist
7566
pytest-asyncio==0.24.0
76-
pytest-timeout==2.3.1
7767
pytest-xdist==3.7.0
78-
python-dateutil==2.8.2
68+
python-dateutil==2.9.0.post0
7969
# via time-machine
80-
pytz==2024.2 ; python_full_version < '3.9'
81-
# via dirty-equals
8270
respx==0.22.0
8371
rich==13.9.4
8472
ruff==0.9.4
@@ -88,36 +76,19 @@ sniffio==1.3.1
8876
# via
8977
# anyio
9078
# runloop-api-client
91-
time-machine==2.15.0 ; python_full_version < '3.9'
92-
time-machine==2.16.0 ; python_full_version >= '3.9'
79+
time-machine==2.16.0
9380
tomli==2.2.1 ; python_full_version < '3.11'
9481
# via
9582
# mypy
9683
# pytest
9784
typing-extensions==4.12.2
9885
# via
99-
# annotated-types
10086
# anyio
10187
# mypy
10288
# pydantic
10389
# pydantic-core
10490
# pyright
10591
# rich
10692
# runloop-api-client
107-
# typing-inspection
108-
typing-inspection==0.4.1 ; python_full_version >= '3.9'
109-
# via pydantic
110-
# via pydantic-core
111-
# via pyright
112-
# via runloop-api-client
113-
# via typing-inspection
114-
typing-inspection==0.4.1
115-
# via pydantic
116-
uuid-utils==0.11.0
117-
# via runloop-api-client
118-
virtualenv==20.24.5
119-
# via nox
120-
yarl==1.20.0
121-
# via aiohttp
122-
zipp>=3.20
93+
zipp==3.21.0
12394
# via importlib-metadata

src/runloop_api_client/_streaming.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ def __stream__(self) -> Iterator[_T]:
8787

8888
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
8989

90-
# Ensure the entire stream is consumed
91-
for _sse in iterator:
92-
...
90+
# As we might not fully consume the response stream, we need to close it explicitly
91+
response.close()
9392

9493
def __enter__(self) -> Self:
9594
return self
@@ -162,9 +161,8 @@ async def __stream__(self) -> AsyncIterator[_T]:
162161

163162
yield process_data(data=sse.json(), cast_to=cast_to, response=response)
164163

165-
# Ensure the entire stream is consumed
166-
async for _sse in iterator:
167-
...
164+
# As we might not fully consume the response stream, we need to close it explicitly
165+
await response.aclose()
168166

169167
async def __aenter__(self) -> Self:
170168
return self

src/runloop_api_client/_utils/_sync.py

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
from __future__ import annotations
22

3-
import sys
43
import asyncio
54
import functools
6-
import contextvars
7-
from typing import Any, TypeVar, Callable, Awaitable
5+
from typing import TypeVar, Callable, Awaitable
86
from typing_extensions import ParamSpec
97

108
import anyio
@@ -15,34 +13,11 @@
1513
T_ParamSpec = ParamSpec("T_ParamSpec")
1614

1715

18-
if sys.version_info >= (3, 9):
19-
_asyncio_to_thread = asyncio.to_thread
20-
else:
21-
# backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread
22-
# for Python 3.8 support
23-
async def _asyncio_to_thread(
24-
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
25-
) -> Any:
26-
"""Asynchronously run function *func* in a separate thread.
27-
28-
Any *args and **kwargs supplied for this function are directly passed
29-
to *func*. Also, the current :class:`contextvars.Context` is propagated,
30-
allowing context variables from the main thread to be accessed in the
31-
separate thread.
32-
33-
Returns a coroutine that can be awaited to get the eventual result of *func*.
34-
"""
35-
loop = asyncio.events.get_running_loop()
36-
ctx = contextvars.copy_context()
37-
func_call = functools.partial(ctx.run, func, *args, **kwargs)
38-
return await loop.run_in_executor(None, func_call)
39-
40-
4116
async def to_thread(
4217
func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs
4318
) -> T_Retval:
4419
if sniffio.current_async_library() == "asyncio":
45-
return await _asyncio_to_thread(func, *args, **kwargs)
20+
return await asyncio.to_thread(func, *args, **kwargs)
4621

4722
return await anyio.to_thread.run_sync(
4823
functools.partial(func, *args, **kwargs),
@@ -53,10 +28,7 @@ async def to_thread(
5328
def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]:
5429
"""
5530
Take a blocking function and create an async one that receives the same
56-
positional and keyword arguments. For python version 3.9 and above, it uses
57-
asyncio.to_thread to run the function in a separate thread. For python version
58-
3.8, it uses locally defined copy of the asyncio.to_thread function which was
59-
introduced in python 3.9.
31+
positional and keyword arguments.
6032
6133
Usage:
6234

src/runloop_api_client/_utils/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]:
133133
# Type safe methods for narrowing types with TypeVars.
134134
# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown],
135135
# however this cause Pyright to rightfully report errors. As we know we don't
136-
# care about the contained types we can safely use `object` in it's place.
136+
# care about the contained types we can safely use `object` in its place.
137137
#
138138
# There are two separate functions defined, `is_*` and `is_*_t` for different use cases.
139139
# `is_*` is for when you're dealing with an unknown input

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__ = "0.66.1" # x-release-please-version
4+
__version__ = "0.67.0" # x-release-please-version

0 commit comments

Comments
 (0)