Skip to content

Commit 742357d

Browse files
Merge pull request #636 from runloopai/release-please--branches--main--changes--next
release: 0.58.0
2 parents 0c86522 + 6d0d0f8 commit 742357d

42 files changed

Lines changed: 971 additions & 206 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.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.57.0"
2+
".": "0.58.0"
33
}

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 100
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-2027ff4b25ad2b5574b2ce497f5d0d02ad8804816ffd6b4e36511e2fa955d0cf.yml
3-
openapi_spec_hash: 54a5a26e9c0b179d2f2a532268d3d711
4-
config_hash: b97411af91b8ec0b8b066358c29091b4
1+
configured_endpoints: 101
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-6b4c63a026f224ec02ccd715e063e07107b545bb859218afaac2b3df84cd227a.yml
3+
openapi_spec_hash: 76072cd766a9c45cff8890bb2bb8b1d5
4+
config_hash: a8ac5e38099129b07ae4decb0774719d

CHANGELOG.md

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

3+
## 0.58.0 (2025-09-04)
4+
5+
Full Changelog: [v0.57.0...v0.58.0](https://github.com/runloopai/api-client-python/compare/v0.57.0...v0.58.0)
6+
7+
### Features
8+
9+
* **api:** api update ([59e649d](https://github.com/runloopai/api-client-python/commit/59e649db1632c06c7c6b7cdabaf7e42e003daa09))
10+
* improve future compat with pydantic v3 ([adb9765](https://github.com/runloopai/api-client-python/commit/adb97652aea509e832ab50f25d7e04e80d8fd09e))
11+
* **types:** replace List[str] with SequenceNotStr in params ([9c3bbcd](https://github.com/runloopai/api-client-python/commit/9c3bbcdfdaedcf60d9829bc3cad83f89c9add98a))
12+
13+
14+
### Chores
15+
16+
* **internal:** add Sequence related utils ([dec07b5](https://github.com/runloopai/api-client-python/commit/dec07b5258bc057375c8412c76f0a7f29f12b723))
17+
318
## 0.57.0 (2025-08-27)
419

520
Full Changelog: [v0.56.2...v0.57.0](https://github.com/runloopai/api-client-python/compare/v0.56.2...v0.57.0)

api.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,19 @@ Methods:
254254

255255
## Executions
256256

257+
Types:
258+
259+
```python
260+
from runloop_api_client.types.devboxes import ExecutionUpdateChunk
261+
```
262+
257263
Methods:
258264

259265
- <code title="get /v1/devboxes/{devbox_id}/executions/{execution_id}">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">retrieve</a>(execution_id, \*, devbox_id, \*\*<a href="src/runloop_api_client/types/devboxes/execution_retrieve_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
260266
- <code title="post /v1/devboxes/{id}/execute_async">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">execute_async</a>(id, \*\*<a href="src/runloop_api_client/types/devboxes/execution_execute_async_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
261267
- <code title="post /v1/devboxes/{id}/execute_sync">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">execute_sync</a>(id, \*\*<a href="src/runloop_api_client/types/devboxes/execution_execute_sync_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_execution_detail_view.py">DevboxExecutionDetailView</a></code>
262-
- <code title="post /v1/devboxes/{devbox_id}/executions/{execution_id}/kill">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">kill</a>(execution_id, \*, devbox_id) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
268+
- <code title="post /v1/devboxes/{devbox_id}/executions/{execution_id}/kill">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">kill</a>(execution_id, \*, devbox_id, \*\*<a href="src/runloop_api_client/types/devboxes/execution_kill_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
269+
- <code title="get /v1/devboxes/{devbox_id}/executions/{execution_id}/stream_updates">client.devboxes.executions.<a href="./src/runloop_api_client/resources/devboxes/executions.py">stream_updates</a>(execution_id, \*, devbox_id, \*\*<a href="src/runloop_api_client/types/devboxes/execution_stream_updates_params.py">params</a>) -> <a href="./src/runloop_api_client/types/devbox_async_execution_detail_view.py">DevboxAsyncExecutionDetailView</a></code>
263270

264271
# Scenarios
265272

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.57.0"
3+
version = "0.58.0"
44
description = "The official Python library for the runloop API"
55
dynamic = ["readme"]
66
license = "MIT"

src/runloop_api_client/_base_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
ModelBuilderProtocol,
6060
)
6161
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
62-
from ._compat import PYDANTIC_V2, model_copy, model_dump
62+
from ._compat import PYDANTIC_V1, model_copy, model_dump
6363
from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
6464
from ._response import (
6565
APIResponse,
@@ -232,7 +232,7 @@ def _set_private_attributes(
232232
model: Type[_T],
233233
options: FinalRequestOptions,
234234
) -> None:
235-
if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
235+
if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
236236
self.__pydantic_private__ = {}
237237

238238
self._model = model
@@ -320,7 +320,7 @@ def _set_private_attributes(
320320
client: AsyncAPIClient,
321321
options: FinalRequestOptions,
322322
) -> None:
323-
if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None:
323+
if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None:
324324
self.__pydantic_private__ = {}
325325

326326
self._model = model

src/runloop_api_client/_compat.py

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
_T = TypeVar("_T")
1313
_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel)
1414

15-
# --------------- Pydantic v2 compatibility ---------------
15+
# --------------- Pydantic v2, v3 compatibility ---------------
1616

1717
# Pyright incorrectly reports some of our functions as overriding a method when they don't
1818
# pyright: reportIncompatibleMethodOverride=false
1919

20-
PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
20+
PYDANTIC_V1 = pydantic.VERSION.startswith("1.")
2121

22-
# v1 re-exports
2322
if TYPE_CHECKING:
2423

2524
def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001
@@ -44,90 +43,92 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001
4443
...
4544

4645
else:
47-
if PYDANTIC_V2:
48-
from pydantic.v1.typing import (
46+
# v1 re-exports
47+
if PYDANTIC_V1:
48+
from pydantic.typing import (
4949
get_args as get_args,
5050
is_union as is_union,
5151
get_origin as get_origin,
5252
is_typeddict as is_typeddict,
5353
is_literal_type as is_literal_type,
5454
)
55-
from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
55+
from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
5656
else:
57-
from pydantic.typing import (
57+
from ._utils import (
5858
get_args as get_args,
5959
is_union as is_union,
6060
get_origin as get_origin,
61+
parse_date as parse_date,
6162
is_typeddict as is_typeddict,
63+
parse_datetime as parse_datetime,
6264
is_literal_type as is_literal_type,
6365
)
64-
from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime
6566

6667

6768
# refactored config
6869
if TYPE_CHECKING:
6970
from pydantic import ConfigDict as ConfigDict
7071
else:
71-
if PYDANTIC_V2:
72-
from pydantic import ConfigDict
73-
else:
72+
if PYDANTIC_V1:
7473
# TODO: provide an error message here?
7574
ConfigDict = None
75+
else:
76+
from pydantic import ConfigDict as ConfigDict
7677

7778

7879
# renamed methods / properties
7980
def parse_obj(model: type[_ModelT], value: object) -> _ModelT:
80-
if PYDANTIC_V2:
81-
return model.model_validate(value)
82-
else:
81+
if PYDANTIC_V1:
8382
return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
83+
else:
84+
return model.model_validate(value)
8485

8586

8687
def field_is_required(field: FieldInfo) -> bool:
87-
if PYDANTIC_V2:
88-
return field.is_required()
89-
return field.required # type: ignore
88+
if PYDANTIC_V1:
89+
return field.required # type: ignore
90+
return field.is_required()
9091

9192

9293
def field_get_default(field: FieldInfo) -> Any:
9394
value = field.get_default()
94-
if PYDANTIC_V2:
95-
from pydantic_core import PydanticUndefined
96-
97-
if value == PydanticUndefined:
98-
return None
95+
if PYDANTIC_V1:
9996
return value
97+
from pydantic_core import PydanticUndefined
98+
99+
if value == PydanticUndefined:
100+
return None
100101
return value
101102

102103

103104
def field_outer_type(field: FieldInfo) -> Any:
104-
if PYDANTIC_V2:
105-
return field.annotation
106-
return field.outer_type_ # type: ignore
105+
if PYDANTIC_V1:
106+
return field.outer_type_ # type: ignore
107+
return field.annotation
107108

108109

109110
def get_model_config(model: type[pydantic.BaseModel]) -> Any:
110-
if PYDANTIC_V2:
111-
return model.model_config
112-
return model.__config__ # type: ignore
111+
if PYDANTIC_V1:
112+
return model.__config__ # type: ignore
113+
return model.model_config
113114

114115

115116
def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]:
116-
if PYDANTIC_V2:
117-
return model.model_fields
118-
return model.__fields__ # type: ignore
117+
if PYDANTIC_V1:
118+
return model.__fields__ # type: ignore
119+
return model.model_fields
119120

120121

121122
def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT:
122-
if PYDANTIC_V2:
123-
return model.model_copy(deep=deep)
124-
return model.copy(deep=deep) # type: ignore
123+
if PYDANTIC_V1:
124+
return model.copy(deep=deep) # type: ignore
125+
return model.model_copy(deep=deep)
125126

126127

127128
def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
128-
if PYDANTIC_V2:
129-
return model.model_dump_json(indent=indent)
130-
return model.json(indent=indent) # type: ignore
129+
if PYDANTIC_V1:
130+
return model.json(indent=indent) # type: ignore
131+
return model.model_dump_json(indent=indent)
131132

132133

133134
def model_dump(
@@ -139,14 +140,14 @@ def model_dump(
139140
warnings: bool = True,
140141
mode: Literal["json", "python"] = "python",
141142
) -> dict[str, Any]:
142-
if PYDANTIC_V2 or hasattr(model, "model_dump"):
143+
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
143144
return model.model_dump(
144145
mode=mode,
145146
exclude=exclude,
146147
exclude_unset=exclude_unset,
147148
exclude_defaults=exclude_defaults,
148149
# warnings are not supported in Pydantic v1
149-
warnings=warnings if PYDANTIC_V2 else True,
150+
warnings=True if PYDANTIC_V1 else warnings,
150151
)
151152
return cast(
152153
"dict[str, Any]",
@@ -159,9 +160,9 @@ def model_dump(
159160

160161

161162
def model_parse(model: type[_ModelT], data: Any) -> _ModelT:
162-
if PYDANTIC_V2:
163-
return model.model_validate(data)
164-
return model.parse_obj(data) # pyright: ignore[reportDeprecated]
163+
if PYDANTIC_V1:
164+
return model.parse_obj(data) # pyright: ignore[reportDeprecated]
165+
return model.model_validate(data)
165166

166167

167168
# generic models
@@ -170,17 +171,16 @@ def model_parse(model: type[_ModelT], data: Any) -> _ModelT:
170171
class GenericModel(pydantic.BaseModel): ...
171172

172173
else:
173-
if PYDANTIC_V2:
174+
if PYDANTIC_V1:
175+
import pydantic.generics
176+
177+
class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ...
178+
else:
174179
# there no longer needs to be a distinction in v2 but
175180
# we still have to create our own subclass to avoid
176181
# inconsistent MRO ordering errors
177182
class GenericModel(pydantic.BaseModel): ...
178183

179-
else:
180-
import pydantic.generics
181-
182-
class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ...
183-
184184

185185
# cached properties
186186
if TYPE_CHECKING:

0 commit comments

Comments
 (0)