Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.prism.log
.vscode
_dev

__pycache__
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.50.0"
".": "0.51.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 92
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-963f8c488e668763300b08860aef9dd85b72c32069ca20e0c36795e86d2938b1.yml
openapi_spec_hash: 65c50f6ab92fd7bf7d108be411923a7a
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-bbb5c731b774122662526cc0b24015828012b1f09bb32fe2d54498aa09e52c92.yml
openapi_spec_hash: 3d23e89561895724da8d48967dd26f17
config_hash: 60681f589a9e641fdb7f19af2021a033
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.analysis.importFormat": "relative",
}
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 0.51.0 (2025-07-29)

Full Changelog: [v0.50.0...v0.51.0](https://github.com/runloopai/api-client-python/compare/v0.50.0...v0.51.0)

### Features

* **api:** api update ([5d42629](https://github.com/runloopai/api-client-python/commit/5d426295ac258ede767c131a209b1deab4d746a6))


### Bug Fixes

* **parsing:** ignore empty metadata ([10c81bd](https://github.com/runloopai/api-client-python/commit/10c81bd7e10ee82e1414aede07c6889630322f6b))
* **parsing:** parse extra field types ([9d2a5f0](https://github.com/runloopai/api-client-python/commit/9d2a5f01e3646d127dec75dca085c2168c35f48a))


### Chores

* **project:** add settings file for vscode ([7a11210](https://github.com/runloopai/api-client-python/commit/7a1121066a7eeb7ca3acb9185834154556d52894))
* **types:** rebuild Pydantic models after all types are defined ([b1839c6](https://github.com/runloopai/api-client-python/commit/b1839c61f42496896ed58b90a983771902f2c26e))

## 0.50.0 (2025-07-15)

Full Changelog: [v0.49.0...v0.50.0](https://github.com/runloopai/api-client-python/compare/v0.49.0...v0.50.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
version = "0.50.0"
version = "0.51.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
Expand Down
27 changes: 24 additions & 3 deletions src/runloop_api_client/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,18 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
else:
fields_values[name] = field_get_default(field)

extra_field_type = _get_extra_fields_type(__cls)

_extra = {}
for key, value in values.items():
if key not in model_fields:
parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value

if PYDANTIC_V2:
_extra[key] = value
_extra[key] = parsed
else:
_fields_set.add(key)
fields_values[key] = value
fields_values[key] = parsed

object.__setattr__(m, "__dict__", fields_values)

Expand Down Expand Up @@ -370,6 +374,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object:
return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))


def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None:
if not PYDANTIC_V2:
# TODO
return None

schema = cls.__pydantic_core_schema__
if schema["type"] == "model":
fields = schema["schema"]
if fields["type"] == "model-fields":
extras = fields.get("extras_schema")
if extras and "cls" in extras:
# mypy can't narrow the type
return extras["cls"] # type: ignore[no-any-return]

return None


def is_basemodel(type_: type) -> bool:
"""Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`"""
if is_union(type_):
Expand Down Expand Up @@ -439,7 +460,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]
type_ = type_.__value__ # type: ignore[unreachable]

# unwrap `Annotated[T, ...]` -> `T`
if metadata is not None:
if metadata is not None and len(metadata) > 0:
meta: tuple[Any, ...] = tuple(metadata)
elif is_annotated_type(type_):
meta = get_args(type_)[1:]
Expand Down
2 changes: 1 addition & 1 deletion src/runloop_api_client/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "runloop_api_client"
__version__ = "0.50.0" # x-release-please-version
__version__ = "0.51.0" # x-release-please-version
40 changes: 40 additions & 0 deletions src/runloop_api_client/resources/devboxes/devboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,9 @@ def upload_file(
id: str,
*,
path: str,
chmod: Optional[str] | NotGiven = NOT_GIVEN,
file: FileTypes | NotGiven = NOT_GIVEN,
owner: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -1324,6 +1326,12 @@ def upload_file(
path: The path to write the file to on the Devbox. Path is relative to user home
directory.

chmod: File permissions in octal format (e.g., "644", "1755"). Optional. If not
specified, default system permissions will be used.

owner: File owner username. Optional. If not specified, the file will be owned by the
current user.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -1341,7 +1349,9 @@ def upload_file(
body = deepcopy_minimal(
{
"path": path,
"chmod": chmod,
"file": file,
"owner": owner,
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
Expand Down Expand Up @@ -1369,6 +1379,8 @@ def write_file_contents(
*,
contents: str,
file_path: str,
chmod: Optional[str] | NotGiven = NOT_GIVEN,
owner: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -1388,6 +1400,12 @@ def write_file_contents(
file_path: The path to write the file to on the Devbox. Path is relative to user home
directory.

chmod: File permissions in octal format (e.g., "644", "1755"). Optional. If not
specified, default system permissions will be used.

owner: File owner username. Optional. If not specified, the file will be owned by the
current user.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -1408,6 +1426,8 @@ def write_file_contents(
{
"contents": contents,
"file_path": file_path,
"chmod": chmod,
"owner": owner,
},
devbox_write_file_contents_params.DevboxWriteFileContentsParams,
),
Expand Down Expand Up @@ -2598,7 +2618,9 @@ async def upload_file(
id: str,
*,
path: str,
chmod: Optional[str] | NotGiven = NOT_GIVEN,
file: FileTypes | NotGiven = NOT_GIVEN,
owner: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -2617,6 +2639,12 @@ async def upload_file(
path: The path to write the file to on the Devbox. Path is relative to user home
directory.

chmod: File permissions in octal format (e.g., "644", "1755"). Optional. If not
specified, default system permissions will be used.

owner: File owner username. Optional. If not specified, the file will be owned by the
current user.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -2634,7 +2662,9 @@ async def upload_file(
body = deepcopy_minimal(
{
"path": path,
"chmod": chmod,
"file": file,
"owner": owner,
}
)
files = extract_files(cast(Mapping[str, object], body), paths=[["file"]])
Expand Down Expand Up @@ -2662,6 +2692,8 @@ async def write_file_contents(
*,
contents: str,
file_path: str,
chmod: Optional[str] | NotGiven = NOT_GIVEN,
owner: Optional[str] | NotGiven = NOT_GIVEN,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
Expand All @@ -2681,6 +2713,12 @@ async def write_file_contents(
file_path: The path to write the file to on the Devbox. Path is relative to user home
directory.

chmod: File permissions in octal format (e.g., "644", "1755"). Optional. If not
specified, default system permissions will be used.

owner: File owner username. Optional. If not specified, the file will be owned by the
current user.

extra_headers: Send extra headers

extra_query: Add additional query parameters to the request
Expand All @@ -2701,6 +2739,8 @@ async def write_file_contents(
{
"contents": contents,
"file_path": file_path,
"chmod": chmod,
"owner": owner,
},
devbox_write_file_contents_params.DevboxWriteFileContentsParams,
),
Expand Down
13 changes: 13 additions & 0 deletions src/runloop_api_client/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

from . import devboxes
from .. import _compat
from .shared import (
AfterIdle as AfterIdle,
LaunchParameters as LaunchParameters,
Expand Down Expand Up @@ -81,3 +83,14 @@
from .devbox_write_file_contents_params import DevboxWriteFileContentsParams as DevboxWriteFileContentsParams
from .devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView as DevboxAsyncExecutionDetailView
from .devbox_read_file_contents_response import DevboxReadFileContentsResponse as DevboxReadFileContentsResponse

# Rebuild cyclical models only after all modules are imported.
# This ensures that, when building the deferred (due to cyclical references) model schema,
# Pydantic can resolve the necessary references.
# See: https://github.com/pydantic/pydantic/issues/11250 for more context.
if _compat.PYDANTIC_V2:
devboxes.code_segment_info_response.CodeSegmentInfoResponse.model_rebuild(_parent_namespace_depth=0)
devboxes.document_symbol.DocumentSymbol.model_rebuild(_parent_namespace_depth=0)
else:
devboxes.code_segment_info_response.CodeSegmentInfoResponse.update_forward_refs() # type: ignore
devboxes.document_symbol.DocumentSymbol.update_forward_refs() # type: ignore
13 changes: 13 additions & 0 deletions src/runloop_api_client/types/devbox_upload_file_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from typing import Optional
from typing_extensions import Required, TypedDict

from .._types import FileTypes
Expand All @@ -16,4 +17,16 @@ class DevboxUploadFileParams(TypedDict, total=False):
Path is relative to user home directory.
"""

chmod: Optional[str]
"""File permissions in octal format (e.g., "644", "1755").

Optional. If not specified, default system permissions will be used.
"""

file: FileTypes

owner: Optional[str]
"""File owner username.

Optional. If not specified, the file will be owned by the current user.
"""
13 changes: 13 additions & 0 deletions src/runloop_api_client/types/devbox_write_file_contents_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from typing import Optional
from typing_extensions import Required, TypedDict

__all__ = ["DevboxWriteFileContentsParams"]
Expand All @@ -16,3 +17,15 @@ class DevboxWriteFileContentsParams(TypedDict, total=False):

Path is relative to user home directory.
"""

chmod: Optional[str]
"""File permissions in octal format (e.g., "644", "1755").

Optional. If not specified, default system permissions will be used.
"""

owner: Optional[str]
"""File owner username.

Optional. If not specified, the file will be owned by the current user.
"""
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from typing import List, Optional

from .file_uri import FileUri
from ..._compat import PYDANTIC_V2
from ..._models import BaseModel
from .base_range import BaseRange
from .base_location import BaseLocation
Expand Down Expand Up @@ -45,10 +44,3 @@ class CodeSegmentInfoResponse(BaseModel):


from .document_symbol import DocumentSymbol

if PYDANTIC_V2:
CodeSegmentInfoResponse.model_rebuild()
Hover.model_rebuild()
else:
CodeSegmentInfoResponse.update_forward_refs() # type: ignore
Hover.update_forward_refs() # type: ignore
10 changes: 2 additions & 8 deletions src/runloop_api_client/types/devboxes/document_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

from __future__ import annotations

from typing import TYPE_CHECKING, List, Optional
from typing import TYPE_CHECKING, Dict, List, Optional

from pydantic import Field as FieldInfo

from .range import Range
from ..._compat import PYDANTIC_V2
from ..._models import BaseModel
from .symbol_tag import SymbolTag
from .symbol_kind import SymbolKind
Expand Down Expand Up @@ -51,14 +50,9 @@ class DocumentSymbol(BaseModel):
tags: Optional[List[SymbolTag]] = None
"""Tags for this document symbol."""

__pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
if TYPE_CHECKING:
# Stub to indicate that arbitrary properties are accepted.
# To access properties that are not valid identifiers you can use `getattr`, e.g.
# `getattr(obj, '$type')`
def __getattr__(self, attr: str) -> object: ...


if PYDANTIC_V2:
DocumentSymbol.model_rebuild()
else:
DocumentSymbol.update_forward_refs() # type: ignore
5 changes: 4 additions & 1 deletion src/runloop_api_client/types/devboxes/position.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Dict

from pydantic import Field as FieldInfo

from .uinteger import Uinteger
from ..._models import BaseModel
Expand All @@ -27,6 +29,7 @@ class Position(BaseModel):
defaults to 0.
"""

__pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
if TYPE_CHECKING:
# Stub to indicate that arbitrary properties are accepted.
# To access properties that are not valid identifiers you can use `getattr`, e.g.
Expand Down
Loading