diff --git a/.gitignore b/.gitignore
index 0f9a66a97..877974080 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.prism.log
.vscode
_dev
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index b56c3d0b4..e8285b710 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.1.0-alpha.4"
+ ".": "0.1.0-alpha.5"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 2049e5bd1..abad5da29 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 15
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-e741833ec80041045f2b16ea82c2bd4c7b2d4b4bf0ec0f5698b20ece98763d00.yml
+configured_endpoints: 14
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-ce4dc6d4d8a6587f304abdd5adf686e08612cab1c5f1cae3cdf8e20ff4a98d2b.yml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4691a9f9..9af1b51ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## 0.1.0-alpha.5 (2024-07-03)
+
+Full Changelog: [v0.1.0-alpha.4...v0.1.0-alpha.5](https://github.com/runloopai/api-client-python/compare/v0.1.0-alpha.4...v0.1.0-alpha.5)
+
+### Features
+
+* **api:** OpenAPI spec update via Stainless API ([#19](https://github.com/runloopai/api-client-python/issues/19)) ([9def751](https://github.com/runloopai/api-client-python/commit/9def7518972cdb0c0a03728408d8e10f79090ba5))
+* **api:** OpenAPI spec update via Stainless API ([#20](https://github.com/runloopai/api-client-python/issues/20)) ([a0bf266](https://github.com/runloopai/api-client-python/commit/a0bf2667f1831d91cc1375328f355dc561b98a37))
+* **api:** OpenAPI spec update via Stainless API ([#21](https://github.com/runloopai/api-client-python/issues/21)) ([9e9f3c2](https://github.com/runloopai/api-client-python/commit/9e9f3c2150928658c49e5c18569411766be60bbe))
+* **api:** OpenAPI spec update via Stainless API ([#22](https://github.com/runloopai/api-client-python/issues/22)) ([5bf8bc0](https://github.com/runloopai/api-client-python/commit/5bf8bc0c5030ed78d04b7a513a0d167aa3e9acf8))
+
## 0.1.0-alpha.4 (2024-06-26)
Full Changelog: [v0.1.0-alpha.3...v0.1.0-alpha.4](https://github.com/runloopai/api-client-python/compare/v0.1.0-alpha.3...v0.1.0-alpha.4)
diff --git a/api.md b/api.md
index 25022156b..92527588e 100644
--- a/api.md
+++ b/api.md
@@ -17,7 +17,7 @@ Methods:
- client.devboxes.create(\*\*params) -> DevboxView
- client.devboxes.retrieve(id) -> DevboxView
- client.devboxes.list(\*\*params) -> DevboxListView
-- client.devboxes.execute_sync(id) -> DevboxExecutionDetailView
+- client.devboxes.execute_sync(id, \*\*params) -> DevboxExecutionDetailView
- client.devboxes.shutdown(id) -> DevboxView
## Logs
@@ -60,18 +60,6 @@ Methods:
- client.functions.invocations.list() -> FunctionInvocationListView
- client.functions.invocations.kill(invocation_id) -> object
-### Spans
-
-Types:
-
-```python
-from runloop_api_client.types.functions.invocations import InvocationSpanListView
-```
-
-Methods:
-
-- client.functions.invocations.spans.list(invocation_id) -> InvocationSpanListView
-
# Projects
Types:
diff --git a/pyproject.toml b/pyproject.toml
index d77d92bc3..6f0a42419 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
-version = "0.1.0-alpha.4"
+version = "0.1.0-alpha.5"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
@@ -58,6 +58,7 @@ dev-dependencies = [
"nox",
"dirty-equals>=0.6.0",
"importlib-metadata>=6.7.0",
+ "rich>=13.7.1",
]
@@ -99,6 +100,21 @@ include = [
[tool.hatch.build.targets.wheel]
packages = ["src/runloop_api_client"]
+[tool.hatch.build.targets.sdist]
+# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc)
+include = [
+ "/*.toml",
+ "/*.json",
+ "/*.lock",
+ "/*.md",
+ "/mypy.ini",
+ "/noxfile.py",
+ "bin/*",
+ "examples/*",
+ "src/*",
+ "tests/*",
+]
+
[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 0852c56d1..18a7b48a4 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -10,7 +10,7 @@
-e file:.
annotated-types==0.6.0
# via pydantic
-anyio==4.1.0
+anyio==4.4.0
# via httpx
# via runloop-api-client
argcomplete==3.1.2
@@ -44,6 +44,10 @@ idna==3.4
importlib-metadata==7.0.0
iniconfig==2.0.0
# via pytest
+markdown-it-py==3.0.0
+ # via rich
+mdurl==0.1.2
+ # via markdown-it-py
mypy==1.7.1
mypy-extensions==1.0.0
# via mypy
@@ -63,6 +67,8 @@ pydantic==2.7.1
# via runloop-api-client
pydantic-core==2.18.2
# via pydantic
+pygments==2.18.0
+ # via rich
pyright==1.1.364
pytest==7.1.1
# via pytest-asyncio
@@ -72,6 +78,7 @@ python-dateutil==2.8.2
pytz==2023.3.post1
# via dirty-equals
respx==0.20.2
+rich==13.7.1
ruff==0.1.9
setuptools==68.2.2
# via nodeenv
@@ -86,6 +93,7 @@ tomli==2.0.1
# via mypy
# via pytest
typing-extensions==4.8.0
+ # via anyio
# via mypy
# via pydantic
# via pydantic-core
diff --git a/requirements.lock b/requirements.lock
index 70c5bb66c..4b4984989 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -10,7 +10,7 @@
-e file:.
annotated-types==0.6.0
# via pydantic
-anyio==4.1.0
+anyio==4.4.0
# via httpx
# via runloop-api-client
certifi==2023.7.22
@@ -38,6 +38,7 @@ sniffio==1.3.0
# via httpx
# via runloop-api-client
typing-extensions==4.8.0
+ # via anyio
# via pydantic
# via pydantic-core
# via runloop-api-client
diff --git a/src/runloop_api_client/_base_client.py b/src/runloop_api_client/_base_client.py
index 7e585689b..8537b9733 100644
--- a/src/runloop_api_client/_base_client.py
+++ b/src/runloop_api_client/_base_client.py
@@ -58,6 +58,7 @@
HttpxSendArgs,
AsyncTransport,
RequestOptions,
+ HttpxRequestFiles,
ModelBuilderProtocol,
)
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
@@ -459,6 +460,7 @@ def _build_request(
headers = self._build_headers(options)
params = _merge_mappings(self.default_query, options.params)
content_type = headers.get("Content-Type")
+ files = options.files
# If the given Content-Type header is multipart/form-data then it
# has to be removed so that httpx can generate the header with
@@ -472,7 +474,7 @@ def _build_request(
headers.pop("Content-Type")
# As we are now sending multipart/form-data instead of application/json
- # we need to tell httpx to use it, https://www.python-httpx.org/advanced/#multipart-file-encoding
+ # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding
if json_data:
if not is_dict(json_data):
raise TypeError(
@@ -480,6 +482,15 @@ def _build_request(
)
kwargs["data"] = self._serialize_multipartform(json_data)
+ # httpx determines whether or not to send a "multipart/form-data"
+ # request based on the truthiness of the "files" argument.
+ # This gets around that issue by generating a dict value that
+ # evaluates to true.
+ #
+ # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186
+ if not files:
+ files = cast(HttpxRequestFiles, ForceMultipartDict())
+
# TODO: report this error to httpx
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
headers=headers,
@@ -492,7 +503,7 @@ def _build_request(
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
json=json_data,
- files=options.files,
+ files=files,
**kwargs,
)
@@ -1863,6 +1874,11 @@ def make_request_options(
return options
+class ForceMultipartDict(Dict[str, None]):
+ def __bool__(self) -> bool:
+ return True
+
+
class OtherPlatform:
def __init__(self, name: str) -> None:
self.name = name
diff --git a/src/runloop_api_client/_client.py b/src/runloop_api_client/_client.py
index 42f5a0422..11b16c4a1 100644
--- a/src/runloop_api_client/_client.py
+++ b/src/runloop_api_client/_client.py
@@ -93,7 +93,7 @@ def __init__(
if base_url is None:
base_url = os.environ.get("RUNLOOP_BASE_URL")
if base_url is None:
- base_url = f"https://api.runloop.pro"
+ base_url = f"https://api.runloop.ai"
super().__init__(
version=__version__,
@@ -265,7 +265,7 @@ def __init__(
if base_url is None:
base_url = os.environ.get("RUNLOOP_BASE_URL")
if base_url is None:
- base_url = f"https://api.runloop.pro"
+ base_url = f"https://api.runloop.ai"
super().__init__(
version=__version__,
diff --git a/src/runloop_api_client/_models.py b/src/runloop_api_client/_models.py
index 75c68cc73..5d95bb4b2 100644
--- a/src/runloop_api_client/_models.py
+++ b/src/runloop_api_client/_models.py
@@ -10,6 +10,7 @@
ClassVar,
Protocol,
Required,
+ ParamSpec,
TypedDict,
TypeGuard,
final,
@@ -67,6 +68,9 @@
__all__ = ["BaseModel", "GenericModel"]
_T = TypeVar("_T")
+_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel")
+
+P = ParamSpec("P")
@runtime_checkable
@@ -379,6 +383,29 @@ def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericMo
return issubclass(origin, BaseModel) or issubclass(origin, GenericModel)
+def build(
+ base_model_cls: Callable[P, _BaseModelT],
+ *args: P.args,
+ **kwargs: P.kwargs,
+) -> _BaseModelT:
+ """Construct a BaseModel class without validation.
+
+ This is useful for cases where you need to instantiate a `BaseModel`
+ from an API response as this provides type-safe params which isn't supported
+ by helpers like `construct_type()`.
+
+ ```py
+ build(MyModel, my_field_a="foo", my_field_b=123)
+ ```
+ """
+ if args:
+ raise TypeError(
+ "Received positional arguments which are not supported; Keyword arguments must be used instead",
+ )
+
+ return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs))
+
+
def construct_type(*, value: object, type_: object) -> object:
"""Loose coercion to the expected type with construction of nested values.
diff --git a/src/runloop_api_client/_utils/__init__.py b/src/runloop_api_client/_utils/__init__.py
index 667e2473f..3efe66c8e 100644
--- a/src/runloop_api_client/_utils/__init__.py
+++ b/src/runloop_api_client/_utils/__init__.py
@@ -49,4 +49,7 @@
maybe_transform as maybe_transform,
async_maybe_transform as async_maybe_transform,
)
-from ._reflection import function_has_argument as function_has_argument
+from ._reflection import (
+ function_has_argument as function_has_argument,
+ assert_signatures_in_sync as assert_signatures_in_sync,
+)
diff --git a/src/runloop_api_client/_utils/_reflection.py b/src/runloop_api_client/_utils/_reflection.py
index e134f58e0..9a53c7bd2 100644
--- a/src/runloop_api_client/_utils/_reflection.py
+++ b/src/runloop_api_client/_utils/_reflection.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import inspect
from typing import Any, Callable
@@ -6,3 +8,35 @@ def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool:
"""Returns whether or not the given function has a specific parameter"""
sig = inspect.signature(func)
return arg_name in sig.parameters
+
+
+def assert_signatures_in_sync(
+ source_func: Callable[..., Any],
+ check_func: Callable[..., Any],
+ *,
+ exclude_params: set[str] = set(),
+) -> None:
+ """Ensure that the signature of the second function matches the first."""
+
+ check_sig = inspect.signature(check_func)
+ source_sig = inspect.signature(source_func)
+
+ errors: list[str] = []
+
+ for name, source_param in source_sig.parameters.items():
+ if name in exclude_params:
+ continue
+
+ custom_param = check_sig.parameters.get(name)
+ if not custom_param:
+ errors.append(f"the `{name}` param is missing")
+ continue
+
+ if custom_param.annotation != source_param.annotation:
+ errors.append(
+ f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(source_param.annotation)}"
+ )
+ continue
+
+ if errors:
+ raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors))
diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py
index 23a34c2b2..8cdc8ca05 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.1.0-alpha.4" # x-release-please-version
+__version__ = "0.1.0-alpha.5" # x-release-please-version
diff --git a/src/runloop_api_client/resources/devboxes/devboxes.py b/src/runloop_api_client/resources/devboxes/devboxes.py
index 2bba79483..7d03a0706 100644
--- a/src/runloop_api_client/resources/devboxes/devboxes.py
+++ b/src/runloop_api_client/resources/devboxes/devboxes.py
@@ -14,7 +14,7 @@
LogsResourceWithStreamingResponse,
AsyncLogsResourceWithStreamingResponse,
)
-from ...types import devbox_list_params, devbox_create_params
+from ...types import devbox_list_params, devbox_create_params, devbox_execute_sync_params
from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ..._utils import (
maybe_transform,
@@ -57,6 +57,7 @@ def create(
code_handle: str | NotGiven = NOT_GIVEN,
entrypoint: str | NotGiven = NOT_GIVEN,
environment_variables: Dict[str, str] | NotGiven = NOT_GIVEN,
+ name: str | NotGiven = NOT_GIVEN,
setup_commands: List[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.
@@ -79,6 +80,8 @@ def create(
environment_variables: (Optional) Environment variables used to configure your Devbox.
+ name: (Optional) A user specified name to give the Devbox.
+
setup_commands: (Optional) List of commands needed to set up your Devbox. Examples might include
fetching a tool or building your dependencies. Runloop will look optimize these
steps for you.
@@ -98,6 +101,7 @@ def create(
"code_handle": code_handle,
"entrypoint": entrypoint,
"environment_variables": environment_variables,
+ "name": name,
"setup_commands": setup_commands,
},
devbox_create_params.DevboxCreateParams,
@@ -185,6 +189,7 @@ def execute_sync(
self,
id: str,
*,
+ command: 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,
@@ -196,6 +201,8 @@ def execute_sync(
Synchronously execute a command on a devbox
Args:
+ command: The command to execute on the Devbox.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -208,6 +215,7 @@ def execute_sync(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
f"/v1/devboxes/{id}/execute_sync",
+ body=maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -268,6 +276,7 @@ async def create(
code_handle: str | NotGiven = NOT_GIVEN,
entrypoint: str | NotGiven = NOT_GIVEN,
environment_variables: Dict[str, str] | NotGiven = NOT_GIVEN,
+ name: str | NotGiven = NOT_GIVEN,
setup_commands: List[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.
@@ -290,6 +299,8 @@ async def create(
environment_variables: (Optional) Environment variables used to configure your Devbox.
+ name: (Optional) A user specified name to give the Devbox.
+
setup_commands: (Optional) List of commands needed to set up your Devbox. Examples might include
fetching a tool or building your dependencies. Runloop will look optimize these
steps for you.
@@ -309,6 +320,7 @@ async def create(
"code_handle": code_handle,
"entrypoint": entrypoint,
"environment_variables": environment_variables,
+ "name": name,
"setup_commands": setup_commands,
},
devbox_create_params.DevboxCreateParams,
@@ -396,6 +408,7 @@ async def execute_sync(
self,
id: str,
*,
+ command: 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,
@@ -407,6 +420,8 @@ async def execute_sync(
Synchronously execute a command on a devbox
Args:
+ command: The command to execute on the Devbox.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -419,6 +434,7 @@ async def execute_sync(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
f"/v1/devboxes/{id}/execute_sync",
+ body=await async_maybe_transform({"command": command}, devbox_execute_sync_params.DevboxExecuteSyncParams),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/runloop_api_client/resources/functions/invocations/__init__.py b/src/runloop_api_client/resources/functions/invocations/__init__.py
index dafa50446..338f27980 100644
--- a/src/runloop_api_client/resources/functions/invocations/__init__.py
+++ b/src/runloop_api_client/resources/functions/invocations/__init__.py
@@ -1,13 +1,5 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from .spans import (
- SpansResource,
- AsyncSpansResource,
- SpansResourceWithRawResponse,
- AsyncSpansResourceWithRawResponse,
- SpansResourceWithStreamingResponse,
- AsyncSpansResourceWithStreamingResponse,
-)
from .invocations import (
InvocationsResource,
AsyncInvocationsResource,
@@ -18,12 +10,6 @@
)
__all__ = [
- "SpansResource",
- "AsyncSpansResource",
- "SpansResourceWithRawResponse",
- "AsyncSpansResourceWithRawResponse",
- "SpansResourceWithStreamingResponse",
- "AsyncSpansResourceWithStreamingResponse",
"InvocationsResource",
"AsyncInvocationsResource",
"InvocationsResourceWithRawResponse",
diff --git a/src/runloop_api_client/resources/functions/invocations/invocations.py b/src/runloop_api_client/resources/functions/invocations/invocations.py
index 66cd346b2..3130b0976 100644
--- a/src/runloop_api_client/resources/functions/invocations/invocations.py
+++ b/src/runloop_api_client/resources/functions/invocations/invocations.py
@@ -4,14 +4,6 @@
import httpx
-from .spans import (
- SpansResource,
- AsyncSpansResource,
- SpansResourceWithRawResponse,
- AsyncSpansResourceWithRawResponse,
- SpansResourceWithStreamingResponse,
- AsyncSpansResourceWithStreamingResponse,
-)
from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from ...._compat import cached_property
from ...._resource import SyncAPIResource, AsyncAPIResource
@@ -31,10 +23,6 @@
class InvocationsResource(SyncAPIResource):
- @cached_property
- def spans(self) -> SpansResource:
- return SpansResource(self._client)
-
@cached_property
def with_raw_response(self) -> InvocationsResourceWithRawResponse:
return InvocationsResourceWithRawResponse(self)
@@ -133,10 +121,6 @@ def kill(
class AsyncInvocationsResource(AsyncAPIResource):
- @cached_property
- def spans(self) -> AsyncSpansResource:
- return AsyncSpansResource(self._client)
-
@cached_property
def with_raw_response(self) -> AsyncInvocationsResourceWithRawResponse:
return AsyncInvocationsResourceWithRawResponse(self)
@@ -248,10 +232,6 @@ def __init__(self, invocations: InvocationsResource) -> None:
invocations.kill,
)
- @cached_property
- def spans(self) -> SpansResourceWithRawResponse:
- return SpansResourceWithRawResponse(self._invocations.spans)
-
class AsyncInvocationsResourceWithRawResponse:
def __init__(self, invocations: AsyncInvocationsResource) -> None:
@@ -267,10 +247,6 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None:
invocations.kill,
)
- @cached_property
- def spans(self) -> AsyncSpansResourceWithRawResponse:
- return AsyncSpansResourceWithRawResponse(self._invocations.spans)
-
class InvocationsResourceWithStreamingResponse:
def __init__(self, invocations: InvocationsResource) -> None:
@@ -286,10 +262,6 @@ def __init__(self, invocations: InvocationsResource) -> None:
invocations.kill,
)
- @cached_property
- def spans(self) -> SpansResourceWithStreamingResponse:
- return SpansResourceWithStreamingResponse(self._invocations.spans)
-
class AsyncInvocationsResourceWithStreamingResponse:
def __init__(self, invocations: AsyncInvocationsResource) -> None:
@@ -304,7 +276,3 @@ def __init__(self, invocations: AsyncInvocationsResource) -> None:
self.kill = async_to_streamed_response_wrapper(
invocations.kill,
)
-
- @cached_property
- def spans(self) -> AsyncSpansResourceWithStreamingResponse:
- return AsyncSpansResourceWithStreamingResponse(self._invocations.spans)
diff --git a/src/runloop_api_client/resources/functions/invocations/spans.py b/src/runloop_api_client/resources/functions/invocations/spans.py
deleted file mode 100644
index 3abe920d9..000000000
--- a/src/runloop_api_client/resources/functions/invocations/spans.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven
-from ...._compat import cached_property
-from ...._resource import SyncAPIResource, AsyncAPIResource
-from ...._response import (
- to_raw_response_wrapper,
- to_streamed_response_wrapper,
- async_to_raw_response_wrapper,
- async_to_streamed_response_wrapper,
-)
-from ...._base_client import (
- make_request_options,
-)
-from ....types.functions.invocations.invocation_span_list_view import InvocationSpanListView
-
-__all__ = ["SpansResource", "AsyncSpansResource"]
-
-
-class SpansResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> SpansResourceWithRawResponse:
- return SpansResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> SpansResourceWithStreamingResponse:
- return SpansResourceWithStreamingResponse(self)
-
- def list(
- self,
- invocation_id: str,
- *,
- # 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,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> InvocationSpanListView:
- """Get the span points for the given invocation.
-
- This will return the span points
- for the invocation.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not invocation_id:
- raise ValueError(f"Expected a non-empty value for `invocation_id` but received {invocation_id!r}")
- return self._get(
- f"/v1/functions/invocations/{invocation_id}/spans",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=InvocationSpanListView,
- )
-
-
-class AsyncSpansResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncSpansResourceWithRawResponse:
- return AsyncSpansResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncSpansResourceWithStreamingResponse:
- return AsyncSpansResourceWithStreamingResponse(self)
-
- async def list(
- self,
- invocation_id: str,
- *,
- # 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,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
- ) -> InvocationSpanListView:
- """Get the span points for the given invocation.
-
- This will return the span points
- for the invocation.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not invocation_id:
- raise ValueError(f"Expected a non-empty value for `invocation_id` but received {invocation_id!r}")
- return await self._get(
- f"/v1/functions/invocations/{invocation_id}/spans",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=InvocationSpanListView,
- )
-
-
-class SpansResourceWithRawResponse:
- def __init__(self, spans: SpansResource) -> None:
- self._spans = spans
-
- self.list = to_raw_response_wrapper(
- spans.list,
- )
-
-
-class AsyncSpansResourceWithRawResponse:
- def __init__(self, spans: AsyncSpansResource) -> None:
- self._spans = spans
-
- self.list = async_to_raw_response_wrapper(
- spans.list,
- )
-
-
-class SpansResourceWithStreamingResponse:
- def __init__(self, spans: SpansResource) -> None:
- self._spans = spans
-
- self.list = to_streamed_response_wrapper(
- spans.list,
- )
-
-
-class AsyncSpansResourceWithStreamingResponse:
- def __init__(self, spans: AsyncSpansResource) -> None:
- self._spans = spans
-
- self.list = async_to_streamed_response_wrapper(
- spans.list,
- )
diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py
index 8cbd8f02b..f31475c02 100644
--- a/src/runloop_api_client/types/__init__.py
+++ b/src/runloop_api_client/types/__init__.py
@@ -9,6 +9,7 @@
from .devbox_list_params import DevboxListParams as DevboxListParams
from .function_list_view import FunctionListView as FunctionListView
from .devbox_create_params import DevboxCreateParams as DevboxCreateParams
+from .devbox_execute_sync_params import DevboxExecuteSyncParams as DevboxExecuteSyncParams
from .function_invoke_sync_params import FunctionInvokeSyncParams as FunctionInvokeSyncParams
from .devbox_execution_detail_view import DevboxExecutionDetailView as DevboxExecutionDetailView
from .function_invoke_async_params import FunctionInvokeAsyncParams as FunctionInvokeAsyncParams
diff --git a/src/runloop_api_client/types/devbox_create_params.py b/src/runloop_api_client/types/devbox_create_params.py
index 588469cf4..49834e010 100644
--- a/src/runloop_api_client/types/devbox_create_params.py
+++ b/src/runloop_api_client/types/devbox_create_params.py
@@ -22,6 +22,9 @@ class DevboxCreateParams(TypedDict, total=False):
environment_variables: Dict[str, str]
"""(Optional) Environment variables used to configure your Devbox."""
+ name: str
+ """(Optional) A user specified name to give the Devbox."""
+
setup_commands: List[str]
"""(Optional) List of commands needed to set up your Devbox.
diff --git a/src/runloop_api_client/types/devbox_execute_sync_params.py b/src/runloop_api_client/types/devbox_execute_sync_params.py
new file mode 100644
index 000000000..12dbc2e0f
--- /dev/null
+++ b/src/runloop_api_client/types/devbox_execute_sync_params.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["DevboxExecuteSyncParams"]
+
+
+class DevboxExecuteSyncParams(TypedDict, total=False):
+ command: str
+ """The command to execute on the Devbox."""
diff --git a/src/runloop_api_client/types/devbox_view.py b/src/runloop_api_client/types/devbox_view.py
index 826b180e9..5dec94295 100644
--- a/src/runloop_api_client/types/devbox_view.py
+++ b/src/runloop_api_client/types/devbox_view.py
@@ -14,6 +14,9 @@ class DevboxView(BaseModel):
create_time_ms: Optional[int] = None
"""Creation time of the Devbox (Unix timestamp milliseconds)."""
+ name: Optional[str] = None
+ """The name of the Devbox."""
+
status: Optional[str] = None
"""
The current status of the Devbox (provisioning, initializing, running, failure,
diff --git a/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py b/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py
index 94fafc41a..e73fec580 100644
--- a/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py
+++ b/src/runloop_api_client/types/devboxes/devbox_logs_list_view.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
+from typing_extensions import Literal
from ..._models import BaseModel
@@ -8,12 +9,24 @@
class Log(BaseModel):
+ cmd: Optional[str] = None
+ """The Command Executed"""
+
+ cmd_id: Optional[str] = None
+ """Identifier of the associated command the log is sourced from."""
+
+ exit_code: Optional[int] = None
+ """The Exit Code of the command"""
+
level: Optional[str] = None
"""Log line severity level."""
message: Optional[str] = None
"""Log line message."""
+ source: Optional[Literal["setup_commands", "entrypoint", "exec"]] = None
+ """The source of the log."""
+
timestamp_ms: Optional[int] = None
"""Time of log (Unix timestamp milliseconds)."""
diff --git a/src/runloop_api_client/types/functions/invocations/__init__.py b/src/runloop_api_client/types/functions/invocations/__init__.py
index 4caaf4299..f8ee8b14b 100644
--- a/src/runloop_api_client/types/functions/invocations/__init__.py
+++ b/src/runloop_api_client/types/functions/invocations/__init__.py
@@ -1,5 +1,3 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
-
-from .invocation_span_list_view import InvocationSpanListView as InvocationSpanListView
diff --git a/src/runloop_api_client/types/functions/invocations/invocation_span_list_view.py b/src/runloop_api_client/types/functions/invocations/invocation_span_list_view.py
deleted file mode 100644
index 786307ae8..000000000
--- a/src/runloop_api_client/types/functions/invocations/invocation_span_list_view.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-
-from pydantic import Field as FieldInfo
-
-from ...._models import BaseModel
-
-__all__ = ["InvocationSpanListView"]
-
-
-class InvocationSpanListView(BaseModel):
- invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None)
-
- spans: Optional[object] = None
- """List of spans matching given query."""
diff --git a/tests/api_resources/functions/invocations/test_spans.py b/tests/api_resources/functions/invocations/test_spans.py
deleted file mode 100644
index a906a79e7..000000000
--- a/tests/api_resources/functions/invocations/test_spans.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Any, cast
-
-import pytest
-
-from tests.utils import assert_matches_type
-from runloop_api_client import Runloop, AsyncRunloop
-from runloop_api_client.types.functions.invocations import InvocationSpanListView
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestSpans:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @parametrize
- def test_method_list(self, client: Runloop) -> None:
- span = client.functions.invocations.spans.list(
- "string",
- )
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- @parametrize
- def test_raw_response_list(self, client: Runloop) -> None:
- response = client.functions.invocations.spans.with_raw_response.list(
- "string",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- span = response.parse()
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- @parametrize
- def test_streaming_response_list(self, client: Runloop) -> None:
- with client.functions.invocations.spans.with_streaming_response.list(
- "string",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- span = response.parse()
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- def test_path_params_list(self, client: Runloop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `invocation_id` but received ''"):
- client.functions.invocations.spans.with_raw_response.list(
- "",
- )
-
-
-class TestAsyncSpans:
- parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @parametrize
- async def test_method_list(self, async_client: AsyncRunloop) -> None:
- span = await async_client.functions.invocations.spans.list(
- "string",
- )
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncRunloop) -> None:
- response = await async_client.functions.invocations.spans.with_raw_response.list(
- "string",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- span = await response.parse()
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncRunloop) -> None:
- async with async_client.functions.invocations.spans.with_streaming_response.list(
- "string",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- span = await response.parse()
- assert_matches_type(InvocationSpanListView, span, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- async def test_path_params_list(self, async_client: AsyncRunloop) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `invocation_id` but received ''"):
- await async_client.functions.invocations.spans.with_raw_response.list(
- "",
- )
diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py
index e1bea0100..b6940e903 100644
--- a/tests/api_resources/test_devboxes.py
+++ b/tests/api_resources/test_devboxes.py
@@ -32,6 +32,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None:
code_handle="string",
entrypoint="string",
environment_variables={"foo": "string"},
+ name="string",
setup_commands=["string", "string", "string"],
)
assert_matches_type(DevboxView, devbox, path=["response"])
@@ -133,6 +134,14 @@ def test_method_execute_sync(self, client: Runloop) -> None:
)
assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"])
+ @parametrize
+ def test_method_execute_sync_with_all_params(self, client: Runloop) -> None:
+ devbox = client.devboxes.execute_sync(
+ "string",
+ command="string",
+ )
+ assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"])
+
@parametrize
def test_raw_response_execute_sync(self, client: Runloop) -> None:
response = client.devboxes.with_raw_response.execute_sync(
@@ -217,6 +226,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) -
code_handle="string",
entrypoint="string",
environment_variables={"foo": "string"},
+ name="string",
setup_commands=["string", "string", "string"],
)
assert_matches_type(DevboxView, devbox, path=["response"])
@@ -318,6 +328,14 @@ async def test_method_execute_sync(self, async_client: AsyncRunloop) -> None:
)
assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"])
+ @parametrize
+ async def test_method_execute_sync_with_all_params(self, async_client: AsyncRunloop) -> None:
+ devbox = await async_client.devboxes.execute_sync(
+ "string",
+ command="string",
+ )
+ assert_matches_type(DevboxExecutionDetailView, devbox, path=["response"])
+
@parametrize
async def test_raw_response_execute_sync(self, async_client: AsyncRunloop) -> None:
response = await async_client.devboxes.with_raw_response.execute_sync(