From ab1191d28943441844e81c6c1189aebc34f54980 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 13 Jan 2026 10:58:40 +0000
Subject: [PATCH 01/25] feat(api): expose device count endpoint
---
.stats.yml | 4 +-
api.md | 3 +-
src/mobilerun/resources/devices/devices.py | 51 +++++++++++++++++
src/mobilerun/types/__init__.py | 1 +
src/mobilerun/types/device_count_response.py | 22 ++++++++
tests/api_resources/test_devices.py | 58 +++++++++++++++++++-
6 files changed, 135 insertions(+), 4 deletions(-)
create mode 100644 src/mobilerun/types/device_count_response.py
diff --git a/.stats.yml b/.stats.yml
index 7a32e45..09bc604 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 49
+configured_endpoints: 50
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-f80ecf1ef8ff0bf85d545b660eeef8677c62d571dc692b47fc044fc82378d330.yml
openapi_spec_hash: 51d80499a2291f8d223276f759392574
-config_hash: 12fc3bd7f141a7f09f5ad38cfa42ba3d
+config_hash: d1f61f26938ee3af50fa5f703318307d
diff --git a/api.md b/api.md
index 20d08ea..0d58a6a 100644
--- a/api.md
+++ b/api.md
@@ -59,7 +59,7 @@ Methods:
Types:
```python
-from mobilerun.types import Device, DeviceListResponse
+from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
```
Methods:
@@ -67,6 +67,7 @@ Methods:
- client.devices.create(\*\*params) -> Device
- client.devices.retrieve(device_id) -> Device
- client.devices.list(\*\*params) -> DeviceListResponse
+- client.devices.count() -> DeviceCountResponse
- client.devices.terminate(device_id) -> None
- client.devices.wait_ready(device_id) -> Device
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
index bc1dbe8..63be619 100644
--- a/src/mobilerun/resources/devices/devices.py
+++ b/src/mobilerun/resources/devices/devices.py
@@ -69,6 +69,7 @@
from ..._base_client import make_request_options
from ...types.device import Device
from ...types.device_list_response import DeviceListResponse
+from ...types.device_count_response import DeviceCountResponse
__all__ = ["DevicesResource", "AsyncDevicesResource"]
@@ -263,6 +264,25 @@ def list(
cast_to=DeviceListResponse,
)
+ def count(
+ self,
+ *,
+ # 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,
+ ) -> DeviceCountResponse:
+ """Count claimed devices"""
+ return self._get(
+ "/devices/count",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DeviceCountResponse,
+ )
+
def terminate(
self,
device_id: str,
@@ -521,6 +541,25 @@ async def list(
cast_to=DeviceListResponse,
)
+ async def count(
+ self,
+ *,
+ # 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,
+ ) -> DeviceCountResponse:
+ """Count claimed devices"""
+ return await self._get(
+ "/devices/count",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DeviceCountResponse,
+ )
+
async def terminate(
self,
device_id: str,
@@ -602,6 +641,9 @@ def __init__(self, devices: DevicesResource) -> None:
self.list = to_raw_response_wrapper(
devices.list,
)
+ self.count = to_raw_response_wrapper(
+ devices.count,
+ )
self.terminate = to_raw_response_wrapper(
devices.terminate,
)
@@ -647,6 +689,9 @@ def __init__(self, devices: AsyncDevicesResource) -> None:
self.list = async_to_raw_response_wrapper(
devices.list,
)
+ self.count = async_to_raw_response_wrapper(
+ devices.count,
+ )
self.terminate = async_to_raw_response_wrapper(
devices.terminate,
)
@@ -692,6 +737,9 @@ def __init__(self, devices: DevicesResource) -> None:
self.list = to_streamed_response_wrapper(
devices.list,
)
+ self.count = to_streamed_response_wrapper(
+ devices.count,
+ )
self.terminate = to_streamed_response_wrapper(
devices.terminate,
)
@@ -737,6 +785,9 @@ def __init__(self, devices: AsyncDevicesResource) -> None:
self.list = async_to_streamed_response_wrapper(
devices.list,
)
+ self.count = async_to_streamed_response_wrapper(
+ devices.count,
+ )
self.terminate = async_to_streamed_response_wrapper(
devices.terminate,
)
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index e5925bb..72eddf4 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -20,6 +20,7 @@
from .device_create_params import DeviceCreateParams as DeviceCreateParams
from .device_list_response import DeviceListResponse as DeviceListResponse
from .hook_update_response import HookUpdateResponse as HookUpdateResponse
+from .device_count_response import DeviceCountResponse as DeviceCountResponse
from .hook_perform_response import HookPerformResponse as HookPerformResponse
from .hook_subscribe_params import HookSubscribeParams as HookSubscribeParams
from .hook_retrieve_response import HookRetrieveResponse as HookRetrieveResponse
diff --git a/src/mobilerun/types/device_count_response.py b/src/mobilerun/types/device_count_response.py
new file mode 100644
index 0000000..517cdeb
--- /dev/null
+++ b/src/mobilerun/types/device_count_response.py
@@ -0,0 +1,22 @@
+# 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__ = ["DeviceCountResponse"]
+
+
+class DeviceCountResponse(BaseModel):
+ limrun: int
+
+ personal: int
+
+ remote: int
+
+ roidrun: int
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py
index 0f3babb..f762064 100644
--- a/tests/api_resources/test_devices.py
+++ b/tests/api_resources/test_devices.py
@@ -9,7 +9,7 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
-from mobilerun.types import Device, DeviceListResponse
+from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -150,6 +150,34 @@ def test_streaming_response_list(self, client: Mobilerun) -> None:
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_count(self, client: Mobilerun) -> None:
+ device = client.devices.count()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_count(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.count()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_count(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.count() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_terminate(self, client: Mobilerun) -> None:
@@ -373,6 +401,34 @@ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> No
assert cast(Any, response.is_closed) is True
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_count(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.count()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_count(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.count()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_count(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.count() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_terminate(self, async_client: AsyncMobilerun) -> None:
From c6668af5dbd83d7ab1dd1fe4f68253422e055e73 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 10:52:57 +0000
Subject: [PATCH 02/25] feat(client): add support for binary request streaming
---
src/mobilerun/_base_client.py | 145 ++++++++++++++++++++++++--
src/mobilerun/_models.py | 17 +++-
src/mobilerun/_types.py | 9 ++
tests/test_client.py | 187 +++++++++++++++++++++++++++++++++-
4 files changed, 344 insertions(+), 14 deletions(-)
diff --git a/src/mobilerun/_base_client.py b/src/mobilerun/_base_client.py
index f24e0dc..5177829 100644
--- a/src/mobilerun/_base_client.py
+++ b/src/mobilerun/_base_client.py
@@ -9,6 +9,7 @@
import inspect
import logging
import platform
+import warnings
import email.utils
from types import TracebackType
from random import random
@@ -51,9 +52,11 @@
ResponseT,
AnyMapping,
PostParser,
+ BinaryTypes,
RequestFiles,
HttpxSendArgs,
RequestOptions,
+ AsyncBinaryTypes,
HttpxRequestFiles,
ModelBuilderProtocol,
not_given,
@@ -477,8 +480,19 @@ def _build_request(
retries_taken: int = 0,
) -> httpx.Request:
if log.isEnabledFor(logging.DEBUG):
- log.debug("Request options: %s", model_dump(options, exclude_unset=True))
-
+ log.debug(
+ "Request options: %s",
+ model_dump(
+ options,
+ exclude_unset=True,
+ # Pydantic v1 can't dump every type we support in content, so we exclude it for now.
+ exclude={
+ "content",
+ }
+ if PYDANTIC_V1
+ else {},
+ ),
+ )
kwargs: dict[str, Any] = {}
json_data = options.json_data
@@ -532,7 +546,13 @@ def _build_request(
is_body_allowed = options.method.lower() != "get"
if is_body_allowed:
- if isinstance(json_data, bytes):
+ if options.content is not None and json_data is not None:
+ raise TypeError("Passing both `content` and `json_data` is not supported")
+ if options.content is not None and files is not None:
+ raise TypeError("Passing both `content` and `files` is not supported")
+ if options.content is not None:
+ kwargs["content"] = options.content
+ elif isinstance(json_data, bytes):
kwargs["content"] = json_data
else:
kwargs["json"] = json_data if is_given(json_data) else None
@@ -1194,6 +1214,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[False] = False,
@@ -1206,6 +1227,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: Literal[True],
@@ -1219,6 +1241,7 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool,
@@ -1231,13 +1254,25 @@ def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
files: RequestFiles | None = None,
stream: bool = False,
stream_cls: type[_StreamT] | None = None,
) -> ResponseT | _StreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
@@ -1247,11 +1282,23 @@ def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1261,11 +1308,23 @@ def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options
)
return self.request(cast_to, opts)
@@ -1275,9 +1334,19 @@ def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: BinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return self.request(cast_to, opts)
def get_api_list(
@@ -1717,6 +1786,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[False] = False,
@@ -1729,6 +1799,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: Literal[True],
@@ -1742,6 +1813,7 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool,
@@ -1754,13 +1826,25 @@ async def post(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
stream: bool = False,
stream_cls: type[_AsyncStreamT] | None = None,
) -> ResponseT | _AsyncStreamT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="post", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
@@ -1770,11 +1854,28 @@ async def patch(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="patch",
+ url=path,
+ json_data=body,
+ content=content,
+ files=await async_to_httpx_files(files),
+ **options,
)
return await self.request(cast_to, opts)
@@ -1784,11 +1885,23 @@ async def put(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
files: RequestFiles | None = None,
options: RequestOptions = {},
) -> ResponseT:
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if files is not None and content is not None:
+ raise TypeError("Passing both `files` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
opts = FinalRequestOptions.construct(
- method="put", url=path, json_data=body, files=await async_to_httpx_files(files), **options
+ method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options
)
return await self.request(cast_to, opts)
@@ -1798,9 +1911,19 @@ async def delete(
*,
cast_to: Type[ResponseT],
body: Body | None = None,
+ content: AsyncBinaryTypes | None = None,
options: RequestOptions = {},
) -> ResponseT:
- opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
+ if body is not None and content is not None:
+ raise TypeError("Passing both `body` and `content` is not supported")
+ if isinstance(body, bytes):
+ warnings.warn(
+ "Passing raw bytes as `body` is deprecated and will be removed in a future version. "
+ "Please pass raw bytes via the `content` parameter instead.",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options)
return await self.request(cast_to, opts)
def get_api_list(
diff --git a/src/mobilerun/_models.py b/src/mobilerun/_models.py
index ca9500b..29070e0 100644
--- a/src/mobilerun/_models.py
+++ b/src/mobilerun/_models.py
@@ -3,7 +3,20 @@
import os
import inspect
import weakref
-from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast
+from typing import (
+ IO,
+ TYPE_CHECKING,
+ Any,
+ Type,
+ Union,
+ Generic,
+ TypeVar,
+ Callable,
+ Iterable,
+ Optional,
+ AsyncIterable,
+ cast,
+)
from datetime import date, datetime
from typing_extensions import (
List,
@@ -787,6 +800,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
timeout: float | Timeout | None
files: HttpxRequestFiles | None
idempotency_key: str
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None]
json_data: Body
extra_json: AnyMapping
follow_redirects: bool
@@ -805,6 +819,7 @@ class FinalRequestOptions(pydantic.BaseModel):
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
follow_redirects: Union[bool, None] = None
+ content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None
# It should be noted that we cannot use `json` here as that would override
# a BaseModel method in an incompatible fashion.
json_data: Union[Body, None] = None
diff --git a/src/mobilerun/_types.py b/src/mobilerun/_types.py
index f9f729e..6fa6541 100644
--- a/src/mobilerun/_types.py
+++ b/src/mobilerun/_types.py
@@ -13,9 +13,11 @@
Mapping,
TypeVar,
Callable,
+ Iterable,
Iterator,
Optional,
Sequence,
+ AsyncIterable,
)
from typing_extensions import (
Set,
@@ -56,6 +58,13 @@
else:
Base64FileInput = Union[IO[bytes], PathLike]
FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8.
+
+
+# Used for sending raw binary data / streaming data in request bodies
+# e.g. for file uploads without multipart encoding
+BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]]
+AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]]
+
FileTypes = Union[
# file (or bytes)
FileContent,
diff --git a/tests/test_client.py b/tests/test_client.py
index add5de8..8c4f9eb 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -8,10 +8,11 @@
import json
import asyncio
import inspect
+import dataclasses
import tracemalloc
-from typing import Any, Union, cast
+from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast
from unittest import mock
-from typing_extensions import Literal
+from typing_extensions import Literal, AsyncIterator, override
import httpx
import pytest
@@ -36,6 +37,7 @@
from .utils import update_env
+T = TypeVar("T")
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
api_key = "My API Key"
@@ -50,6 +52,57 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float:
return 0.1
+def mirror_request_content(request: httpx.Request) -> httpx.Response:
+ return httpx.Response(200, content=request.content)
+
+
+# note: we can't use the httpx.MockTransport class as it consumes the request
+# body itself, which means we can't test that the body is read lazily
+class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport):
+ def __init__(
+ self,
+ handler: Callable[[httpx.Request], httpx.Response]
+ | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]],
+ ) -> None:
+ self.handler = handler
+
+ @override
+ def handle_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function"
+ assert inspect.isfunction(self.handler), "handler must be a function"
+ return self.handler(request)
+
+ @override
+ async def handle_async_request(
+ self,
+ request: httpx.Request,
+ ) -> httpx.Response:
+ assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function"
+ return await self.handler(request)
+
+
+@dataclasses.dataclass
+class Counter:
+ value: int = 0
+
+
+def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
+async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]:
+ for item in iterable:
+ if counter:
+ counter.value += 1
+ yield item
+
+
def _get_open_connections(client: Mobilerun | AsyncMobilerun) -> int:
transport = client._client._transport
assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport)
@@ -511,6 +564,70 @@ def test_multipart_repeating_array(self, client: Mobilerun) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload(self, respx_mock: MockRouter, client: Mobilerun) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ def test_binary_content_upload_with_iterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_sync_iterator([file_content], counter=counter)
+
+ def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=request.read())
+
+ with Mobilerun(
+ base_url=base_url,
+ api_key=api_key,
+ _strict_response_validation=True,
+ http_client=httpx.Client(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Mobilerun) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
def test_basic_union_response(self, respx_mock: MockRouter, client: Mobilerun) -> None:
class Model1(BaseModel):
@@ -1339,6 +1456,72 @@ def test_multipart_repeating_array(self, async_client: AsyncMobilerun) -> None:
b"",
]
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncMobilerun) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ response = await async_client.post(
+ "/upload",
+ content=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
+ async def test_binary_content_upload_with_asynciterator(self) -> None:
+ file_content = b"Hello, this is a test file."
+ counter = Counter()
+ iterator = _make_async_iterator([file_content], counter=counter)
+
+ async def mock_handler(request: httpx.Request) -> httpx.Response:
+ assert counter.value == 0, "the request body should not have been read"
+ return httpx.Response(200, content=await request.aread())
+
+ async with AsyncMobilerun(
+ base_url=base_url,
+ api_key=api_key,
+ _strict_response_validation=True,
+ http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)),
+ ) as client:
+ response = await client.post(
+ "/upload",
+ content=iterator,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+ assert counter.value == 1
+
+ @pytest.mark.respx(base_url=base_url)
+ async def test_binary_content_upload_with_body_is_deprecated(
+ self, respx_mock: MockRouter, async_client: AsyncMobilerun
+ ) -> None:
+ respx_mock.post("/upload").mock(side_effect=mirror_request_content)
+
+ file_content = b"Hello, this is a test file."
+
+ with pytest.deprecated_call(
+ match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead."
+ ):
+ response = await async_client.post(
+ "/upload",
+ body=file_content,
+ cast_to=httpx.Response,
+ options={"headers": {"Content-Type": "application/octet-stream"}},
+ )
+
+ assert response.status_code == 200
+ assert response.request.headers["Content-Type"] == "application/octet-stream"
+ assert response.content == file_content
+
@pytest.mark.respx(base_url=base_url)
async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncMobilerun) -> None:
class Model1(BaseModel):
From 416142eb345a07aefea8404a97231ed0acd74678 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 14:42:28 +0000
Subject: [PATCH 03/25] feat(api): api update
---
.stats.yml | 6 +-
README.md | 20 -
api.md | 86 --
src/mobilerun/_client.py | 39 +-
src/mobilerun/resources/__init__.py | 14 -
src/mobilerun/resources/devices/__init__.py | 103 ---
src/mobilerun/resources/devices/actions.py | 424 ---------
src/mobilerun/resources/devices/apps.py | 495 -----------
src/mobilerun/resources/devices/devices.py | 820 ------------------
src/mobilerun/resources/devices/keyboard.py | 390 ---------
src/mobilerun/resources/devices/packages.py | 195 -----
src/mobilerun/resources/devices/state.py | 385 --------
src/mobilerun/resources/devices/tasks.py | 199 -----
src/mobilerun/types/__init__.py | 5 -
src/mobilerun/types/device.py | 47 -
src/mobilerun/types/device_count_response.py | 22 -
src/mobilerun/types/device_create_params.py | 40 -
src/mobilerun/types/device_list_params.py | 29 -
src/mobilerun/types/device_list_response.py | 33 -
src/mobilerun/types/devices/__init__.py | 19 -
.../types/devices/action_global_params.py | 15 -
.../types/devices/action_swipe_params.py | 24 -
.../types/devices/action_tap_params.py | 17 -
.../types/devices/app_install_params.py | 15 -
.../types/devices/app_list_params.py | 15 -
.../types/devices/app_list_response.py | 25 -
.../types/devices/app_start_params.py | 17 -
.../types/devices/keyboard_key_params.py | 15 -
.../types/devices/keyboard_write_params.py | 17 -
.../types/devices/package_list_params.py | 15 -
.../types/devices/package_list_response.py | 8 -
.../types/devices/state_screenshot_params.py | 15 -
.../devices/state_screenshot_response.py | 7 -
.../types/devices/state_time_response.py | 7 -
.../types/devices/state_ui_params.py | 15 -
.../types/devices/state_ui_response.py | 91 --
.../types/devices/task_list_params.py | 19 -
.../types/devices/task_list_response.py | 41 -
tests/api_resources/devices/__init__.py | 1 -
tests/api_resources/devices/test_actions.py | 408 ---------
tests/api_resources/devices/test_apps.py | 490 -----------
tests/api_resources/devices/test_keyboard.py | 358 --------
tests/api_resources/devices/test_packages.py | 128 ---
tests/api_resources/devices/test_state.py | 336 -------
tests/api_resources/devices/test_tasks.py | 132 ---
tests/api_resources/test_devices.py | 514 -----------
46 files changed, 4 insertions(+), 6112 deletions(-)
delete mode 100644 src/mobilerun/resources/devices/__init__.py
delete mode 100644 src/mobilerun/resources/devices/actions.py
delete mode 100644 src/mobilerun/resources/devices/apps.py
delete mode 100644 src/mobilerun/resources/devices/devices.py
delete mode 100644 src/mobilerun/resources/devices/keyboard.py
delete mode 100644 src/mobilerun/resources/devices/packages.py
delete mode 100644 src/mobilerun/resources/devices/state.py
delete mode 100644 src/mobilerun/resources/devices/tasks.py
delete mode 100644 src/mobilerun/types/device.py
delete mode 100644 src/mobilerun/types/device_count_response.py
delete mode 100644 src/mobilerun/types/device_create_params.py
delete mode 100644 src/mobilerun/types/device_list_params.py
delete mode 100644 src/mobilerun/types/device_list_response.py
delete mode 100644 src/mobilerun/types/devices/action_global_params.py
delete mode 100644 src/mobilerun/types/devices/action_swipe_params.py
delete mode 100644 src/mobilerun/types/devices/action_tap_params.py
delete mode 100644 src/mobilerun/types/devices/app_install_params.py
delete mode 100644 src/mobilerun/types/devices/app_list_params.py
delete mode 100644 src/mobilerun/types/devices/app_list_response.py
delete mode 100644 src/mobilerun/types/devices/app_start_params.py
delete mode 100644 src/mobilerun/types/devices/keyboard_key_params.py
delete mode 100644 src/mobilerun/types/devices/keyboard_write_params.py
delete mode 100644 src/mobilerun/types/devices/package_list_params.py
delete mode 100644 src/mobilerun/types/devices/package_list_response.py
delete mode 100644 src/mobilerun/types/devices/state_screenshot_params.py
delete mode 100644 src/mobilerun/types/devices/state_screenshot_response.py
delete mode 100644 src/mobilerun/types/devices/state_time_response.py
delete mode 100644 src/mobilerun/types/devices/state_ui_params.py
delete mode 100644 src/mobilerun/types/devices/state_ui_response.py
delete mode 100644 src/mobilerun/types/devices/task_list_params.py
delete mode 100644 src/mobilerun/types/devices/task_list_response.py
delete mode 100644 tests/api_resources/devices/__init__.py
delete mode 100644 tests/api_resources/devices/test_actions.py
delete mode 100644 tests/api_resources/devices/test_apps.py
delete mode 100644 tests/api_resources/devices/test_keyboard.py
delete mode 100644 tests/api_resources/devices/test_packages.py
delete mode 100644 tests/api_resources/devices/test_state.py
delete mode 100644 tests/api_resources/devices/test_tasks.py
delete mode 100644 tests/api_resources/test_devices.py
diff --git a/.stats.yml b/.stats.yml
index 09bc604..d703f41 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-f80ecf1ef8ff0bf85d545b660eeef8677c62d571dc692b47fc044fc82378d330.yml
-openapi_spec_hash: 51d80499a2291f8d223276f759392574
+configured_endpoints: 29
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-9bc196694afd948cfd36c21c4779815df718b41928ded5b93760f4d6afa853ef.yml
+openapi_spec_hash: dd56ae43482890faf056c390294ecff5
config_hash: d1f61f26938ee3af50fa5f703318307d
diff --git a/README.md b/README.md
index 0eece63..84c1f14 100644
--- a/README.md
+++ b/README.md
@@ -115,26 +115,6 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
-## Nested params
-
-Nested parameters are dictionaries, typed using `TypedDict`, for example:
-
-```python
-from mobilerun import Mobilerun
-
-client = Mobilerun()
-
-device = client.devices.create(
- proxy={
- "host": "host",
- "password": "password",
- "port": 0,
- "user": "user",
- },
-)
-print(device.proxy)
-```
-
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `mobilerun.APIConnectionError` is raised.
diff --git a/api.md b/api.md
index 0d58a6a..f518023 100644
--- a/api.md
+++ b/api.md
@@ -54,92 +54,6 @@ Methods:
- client.tasks.ui_states.retrieve(index, \*, task_id) -> MediaResponse
- client.tasks.ui_states.list(task_id) -> UiStateListResponse
-# Devices
-
-Types:
-
-```python
-from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
-```
-
-Methods:
-
-- client.devices.create(\*\*params) -> Device
-- client.devices.retrieve(device_id) -> Device
-- client.devices.list(\*\*params) -> DeviceListResponse
-- client.devices.count() -> DeviceCountResponse
-- client.devices.terminate(device_id) -> None
-- client.devices.wait_ready(device_id) -> Device
-
-## Actions
-
-Methods:
-
-- client.devices.actions.global\_(device_id, \*\*params) -> None
-- client.devices.actions.swipe(device_id, \*\*params) -> None
-- client.devices.actions.tap(device_id, \*\*params) -> None
-
-## State
-
-Types:
-
-```python
-from mobilerun.types.devices import StateScreenshotResponse, StateTimeResponse, StateUiResponse
-```
-
-Methods:
-
-- client.devices.state.screenshot(device_id, \*\*params) -> str
-- client.devices.state.time(device_id) -> str
-- client.devices.state.ui(device_id, \*\*params) -> StateUiResponse
-
-## Apps
-
-Types:
-
-```python
-from mobilerun.types.devices import AppListResponse
-```
-
-Methods:
-
-- client.devices.apps.list(device_id, \*\*params) -> Optional[AppListResponse]
-- client.devices.apps.delete(package_name, \*, device_id) -> None
-- client.devices.apps.install(device_id, \*\*params) -> None
-- client.devices.apps.start(package_name, \*, device_id, \*\*params) -> None
-
-## Packages
-
-Types:
-
-```python
-from mobilerun.types.devices import PackageListResponse
-```
-
-Methods:
-
-- client.devices.packages.list(device_id, \*\*params) -> Optional[PackageListResponse]
-
-## Keyboard
-
-Methods:
-
-- client.devices.keyboard.clear(device_id) -> None
-- client.devices.keyboard.key(device_id, \*\*params) -> None
-- client.devices.keyboard.write(device_id, \*\*params) -> None
-
-## Tasks
-
-Types:
-
-```python
-from mobilerun.types.devices import TaskListResponse
-```
-
-Methods:
-
-- client.devices.tasks.list(device_id, \*\*params) -> TaskListResponse
-
# Apps
Types:
diff --git a/src/mobilerun/_client.py b/src/mobilerun/_client.py
index dd728b1..271bb95 100644
--- a/src/mobilerun/_client.py
+++ b/src/mobilerun/_client.py
@@ -32,11 +32,10 @@
)
if TYPE_CHECKING:
- from .resources import apps, hooks, tasks, devices, credentials
+ from .resources import apps, hooks, tasks, credentials
from .resources.apps import AppsResource, AsyncAppsResource
from .resources.hooks import HooksResource, AsyncHooksResource
from .resources.tasks.tasks import TasksResource, AsyncTasksResource
- from .resources.devices.devices import DevicesResource, AsyncDevicesResource
from .resources.credentials.credentials import CredentialsResource, AsyncCredentialsResource
__all__ = [
@@ -108,12 +107,6 @@ def tasks(self) -> TasksResource:
return TasksResource(self)
- @cached_property
- def devices(self) -> DevicesResource:
- from .resources.devices import DevicesResource
-
- return DevicesResource(self)
-
@cached_property
def apps(self) -> AppsResource:
from .resources.apps import AppsResource
@@ -313,12 +306,6 @@ def tasks(self) -> AsyncTasksResource:
return AsyncTasksResource(self)
- @cached_property
- def devices(self) -> AsyncDevicesResource:
- from .resources.devices import AsyncDevicesResource
-
- return AsyncDevicesResource(self)
-
@cached_property
def apps(self) -> AsyncAppsResource:
from .resources.apps import AsyncAppsResource
@@ -473,12 +460,6 @@ def tasks(self) -> tasks.TasksResourceWithRawResponse:
return TasksResourceWithRawResponse(self._client.tasks)
- @cached_property
- def devices(self) -> devices.DevicesResourceWithRawResponse:
- from .resources.devices import DevicesResourceWithRawResponse
-
- return DevicesResourceWithRawResponse(self._client.devices)
-
@cached_property
def apps(self) -> apps.AppsResourceWithRawResponse:
from .resources.apps import AppsResourceWithRawResponse
@@ -510,12 +491,6 @@ def tasks(self) -> tasks.AsyncTasksResourceWithRawResponse:
return AsyncTasksResourceWithRawResponse(self._client.tasks)
- @cached_property
- def devices(self) -> devices.AsyncDevicesResourceWithRawResponse:
- from .resources.devices import AsyncDevicesResourceWithRawResponse
-
- return AsyncDevicesResourceWithRawResponse(self._client.devices)
-
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithRawResponse:
from .resources.apps import AsyncAppsResourceWithRawResponse
@@ -547,12 +522,6 @@ def tasks(self) -> tasks.TasksResourceWithStreamingResponse:
return TasksResourceWithStreamingResponse(self._client.tasks)
- @cached_property
- def devices(self) -> devices.DevicesResourceWithStreamingResponse:
- from .resources.devices import DevicesResourceWithStreamingResponse
-
- return DevicesResourceWithStreamingResponse(self._client.devices)
-
@cached_property
def apps(self) -> apps.AppsResourceWithStreamingResponse:
from .resources.apps import AppsResourceWithStreamingResponse
@@ -584,12 +553,6 @@ def tasks(self) -> tasks.AsyncTasksResourceWithStreamingResponse:
return AsyncTasksResourceWithStreamingResponse(self._client.tasks)
- @cached_property
- def devices(self) -> devices.AsyncDevicesResourceWithStreamingResponse:
- from .resources.devices import AsyncDevicesResourceWithStreamingResponse
-
- return AsyncDevicesResourceWithStreamingResponse(self._client.devices)
-
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithStreamingResponse:
from .resources.apps import AsyncAppsResourceWithStreamingResponse
diff --git a/src/mobilerun/resources/__init__.py b/src/mobilerun/resources/__init__.py
index c65175f..9204f81 100644
--- a/src/mobilerun/resources/__init__.py
+++ b/src/mobilerun/resources/__init__.py
@@ -24,14 +24,6 @@
TasksResourceWithStreamingResponse,
AsyncTasksResourceWithStreamingResponse,
)
-from .devices import (
- DevicesResource,
- AsyncDevicesResource,
- DevicesResourceWithRawResponse,
- AsyncDevicesResourceWithRawResponse,
- DevicesResourceWithStreamingResponse,
- AsyncDevicesResourceWithStreamingResponse,
-)
from .credentials import (
CredentialsResource,
AsyncCredentialsResource,
@@ -48,12 +40,6 @@
"AsyncTasksResourceWithRawResponse",
"TasksResourceWithStreamingResponse",
"AsyncTasksResourceWithStreamingResponse",
- "DevicesResource",
- "AsyncDevicesResource",
- "DevicesResourceWithRawResponse",
- "AsyncDevicesResourceWithRawResponse",
- "DevicesResourceWithStreamingResponse",
- "AsyncDevicesResourceWithStreamingResponse",
"AppsResource",
"AsyncAppsResource",
"AppsResourceWithRawResponse",
diff --git a/src/mobilerun/resources/devices/__init__.py b/src/mobilerun/resources/devices/__init__.py
deleted file mode 100644
index db9559e..0000000
--- a/src/mobilerun/resources/devices/__init__.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .apps import (
- AppsResource,
- AsyncAppsResource,
- AppsResourceWithRawResponse,
- AsyncAppsResourceWithRawResponse,
- AppsResourceWithStreamingResponse,
- AsyncAppsResourceWithStreamingResponse,
-)
-from .state import (
- StateResource,
- AsyncStateResource,
- StateResourceWithRawResponse,
- AsyncStateResourceWithRawResponse,
- StateResourceWithStreamingResponse,
- AsyncStateResourceWithStreamingResponse,
-)
-from .tasks import (
- TasksResource,
- AsyncTasksResource,
- TasksResourceWithRawResponse,
- AsyncTasksResourceWithRawResponse,
- TasksResourceWithStreamingResponse,
- AsyncTasksResourceWithStreamingResponse,
-)
-from .actions import (
- ActionsResource,
- AsyncActionsResource,
- ActionsResourceWithRawResponse,
- AsyncActionsResourceWithRawResponse,
- ActionsResourceWithStreamingResponse,
- AsyncActionsResourceWithStreamingResponse,
-)
-from .devices import (
- DevicesResource,
- AsyncDevicesResource,
- DevicesResourceWithRawResponse,
- AsyncDevicesResourceWithRawResponse,
- DevicesResourceWithStreamingResponse,
- AsyncDevicesResourceWithStreamingResponse,
-)
-from .keyboard import (
- KeyboardResource,
- AsyncKeyboardResource,
- KeyboardResourceWithRawResponse,
- AsyncKeyboardResourceWithRawResponse,
- KeyboardResourceWithStreamingResponse,
- AsyncKeyboardResourceWithStreamingResponse,
-)
-from .packages import (
- PackagesResource,
- AsyncPackagesResource,
- PackagesResourceWithRawResponse,
- AsyncPackagesResourceWithRawResponse,
- PackagesResourceWithStreamingResponse,
- AsyncPackagesResourceWithStreamingResponse,
-)
-
-__all__ = [
- "ActionsResource",
- "AsyncActionsResource",
- "ActionsResourceWithRawResponse",
- "AsyncActionsResourceWithRawResponse",
- "ActionsResourceWithStreamingResponse",
- "AsyncActionsResourceWithStreamingResponse",
- "StateResource",
- "AsyncStateResource",
- "StateResourceWithRawResponse",
- "AsyncStateResourceWithRawResponse",
- "StateResourceWithStreamingResponse",
- "AsyncStateResourceWithStreamingResponse",
- "AppsResource",
- "AsyncAppsResource",
- "AppsResourceWithRawResponse",
- "AsyncAppsResourceWithRawResponse",
- "AppsResourceWithStreamingResponse",
- "AsyncAppsResourceWithStreamingResponse",
- "PackagesResource",
- "AsyncPackagesResource",
- "PackagesResourceWithRawResponse",
- "AsyncPackagesResourceWithRawResponse",
- "PackagesResourceWithStreamingResponse",
- "AsyncPackagesResourceWithStreamingResponse",
- "KeyboardResource",
- "AsyncKeyboardResource",
- "KeyboardResourceWithRawResponse",
- "AsyncKeyboardResourceWithRawResponse",
- "KeyboardResourceWithStreamingResponse",
- "AsyncKeyboardResourceWithStreamingResponse",
- "TasksResource",
- "AsyncTasksResource",
- "TasksResourceWithRawResponse",
- "AsyncTasksResourceWithRawResponse",
- "TasksResourceWithStreamingResponse",
- "AsyncTasksResourceWithStreamingResponse",
- "DevicesResource",
- "AsyncDevicesResource",
- "DevicesResourceWithRawResponse",
- "AsyncDevicesResourceWithRawResponse",
- "DevicesResourceWithStreamingResponse",
- "AsyncDevicesResourceWithStreamingResponse",
-]
diff --git a/src/mobilerun/resources/devices/actions.py b/src/mobilerun/resources/devices/actions.py
deleted file mode 100644
index b0e404a..0000000
--- a/src/mobilerun/resources/devices/actions.py
+++ /dev/null
@@ -1,424 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
-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.devices import action_tap_params, action_swipe_params, action_global_params
-
-__all__ = ["ActionsResource", "AsyncActionsResource"]
-
-
-class ActionsResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> ActionsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return ActionsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> ActionsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return ActionsResourceWithStreamingResponse(self)
-
- def global_(
- self,
- device_id: str,
- *,
- action: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Perform a global action
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/devices/{device_id}/global",
- body=maybe_transform({"action": action}, action_global_params.ActionGlobalParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def swipe(
- self,
- device_id: str,
- *,
- duration: int,
- end_x: int,
- end_y: int,
- start_x: int,
- start_y: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Swipe
-
- Args:
- duration: Swipe duration in milliseconds
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/devices/{device_id}/swipe",
- body=maybe_transform(
- {
- "duration": duration,
- "end_x": end_x,
- "end_y": end_y,
- "start_x": start_x,
- "start_y": start_y,
- },
- action_swipe_params.ActionSwipeParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def tap(
- self,
- device_id: str,
- *,
- x: int,
- y: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Tap by coordinates
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/devices/{device_id}/tap",
- body=maybe_transform(
- {
- "x": x,
- "y": y,
- },
- action_tap_params.ActionTapParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class AsyncActionsResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncActionsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncActionsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncActionsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncActionsResourceWithStreamingResponse(self)
-
- async def global_(
- self,
- device_id: str,
- *,
- action: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Perform a global action
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/devices/{device_id}/global",
- body=await async_maybe_transform({"action": action}, action_global_params.ActionGlobalParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def swipe(
- self,
- device_id: str,
- *,
- duration: int,
- end_x: int,
- end_y: int,
- start_x: int,
- start_y: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Swipe
-
- Args:
- duration: Swipe duration in milliseconds
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/devices/{device_id}/swipe",
- body=await async_maybe_transform(
- {
- "duration": duration,
- "end_x": end_x,
- "end_y": end_y,
- "start_x": start_x,
- "start_y": start_y,
- },
- action_swipe_params.ActionSwipeParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def tap(
- self,
- device_id: str,
- *,
- x: int,
- y: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Tap by coordinates
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/devices/{device_id}/tap",
- body=await async_maybe_transform(
- {
- "x": x,
- "y": y,
- },
- action_tap_params.ActionTapParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class ActionsResourceWithRawResponse:
- def __init__(self, actions: ActionsResource) -> None:
- self._actions = actions
-
- self.global_ = to_raw_response_wrapper(
- actions.global_,
- )
- self.swipe = to_raw_response_wrapper(
- actions.swipe,
- )
- self.tap = to_raw_response_wrapper(
- actions.tap,
- )
-
-
-class AsyncActionsResourceWithRawResponse:
- def __init__(self, actions: AsyncActionsResource) -> None:
- self._actions = actions
-
- self.global_ = async_to_raw_response_wrapper(
- actions.global_,
- )
- self.swipe = async_to_raw_response_wrapper(
- actions.swipe,
- )
- self.tap = async_to_raw_response_wrapper(
- actions.tap,
- )
-
-
-class ActionsResourceWithStreamingResponse:
- def __init__(self, actions: ActionsResource) -> None:
- self._actions = actions
-
- self.global_ = to_streamed_response_wrapper(
- actions.global_,
- )
- self.swipe = to_streamed_response_wrapper(
- actions.swipe,
- )
- self.tap = to_streamed_response_wrapper(
- actions.tap,
- )
-
-
-class AsyncActionsResourceWithStreamingResponse:
- def __init__(self, actions: AsyncActionsResource) -> None:
- self._actions = actions
-
- self.global_ = async_to_streamed_response_wrapper(
- actions.global_,
- )
- self.swipe = async_to_streamed_response_wrapper(
- actions.swipe,
- )
- self.tap = async_to_streamed_response_wrapper(
- actions.tap,
- )
diff --git a/src/mobilerun/resources/devices/apps.py b/src/mobilerun/resources/devices/apps.py
deleted file mode 100644
index e0ddd9b..0000000
--- a/src/mobilerun/resources/devices/apps.py
+++ /dev/null
@@ -1,495 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
-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.devices import app_list_params, app_start_params, app_install_params
-from ...types.devices.app_list_response import AppListResponse
-
-__all__ = ["AppsResource", "AsyncAppsResource"]
-
-
-class AppsResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AppsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AppsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AppsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AppsResourceWithStreamingResponse(self)
-
- def list(
- self,
- device_id: str,
- *,
- include_system_apps: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> Optional[AppListResponse]:
- """
- List apps
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._get(
- f"/devices/{device_id}/apps",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform({"include_system_apps": include_system_apps}, app_list_params.AppListParams),
- ),
- cast_to=AppListResponse,
- )
-
- def delete(
- self,
- package_name: str,
- *,
- device_id: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Delete app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- if not package_name:
- raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._delete(
- f"/devices/{device_id}/apps/{package_name}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def install(
- self,
- device_id: str,
- *,
- package_name: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Install app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/devices/{device_id}/apps",
- body=maybe_transform({"package_name": package_name}, app_install_params.AppInstallParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def start(
- self,
- package_name: str,
- *,
- device_id: str,
- activity: str | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Start app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- if not package_name:
- raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._put(
- f"/devices/{device_id}/apps/{package_name}",
- body=maybe_transform({"activity": activity}, app_start_params.AppStartParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class AsyncAppsResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncAppsResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncAppsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncAppsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncAppsResourceWithStreamingResponse(self)
-
- async def list(
- self,
- device_id: str,
- *,
- include_system_apps: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> Optional[AppListResponse]:
- """
- List apps
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._get(
- f"/devices/{device_id}/apps",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"include_system_apps": include_system_apps}, app_list_params.AppListParams
- ),
- ),
- cast_to=AppListResponse,
- )
-
- async def delete(
- self,
- package_name: str,
- *,
- device_id: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Delete app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- if not package_name:
- raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._delete(
- f"/devices/{device_id}/apps/{package_name}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def install(
- self,
- device_id: str,
- *,
- package_name: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Install app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/devices/{device_id}/apps",
- body=await async_maybe_transform({"package_name": package_name}, app_install_params.AppInstallParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def start(
- self,
- package_name: str,
- *,
- device_id: str,
- activity: str | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Start app
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- if not package_name:
- raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._put(
- f"/devices/{device_id}/apps/{package_name}",
- body=await async_maybe_transform({"activity": activity}, app_start_params.AppStartParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class AppsResourceWithRawResponse:
- def __init__(self, apps: AppsResource) -> None:
- self._apps = apps
-
- self.list = to_raw_response_wrapper(
- apps.list,
- )
- self.delete = to_raw_response_wrapper(
- apps.delete,
- )
- self.install = to_raw_response_wrapper(
- apps.install,
- )
- self.start = to_raw_response_wrapper(
- apps.start,
- )
-
-
-class AsyncAppsResourceWithRawResponse:
- def __init__(self, apps: AsyncAppsResource) -> None:
- self._apps = apps
-
- self.list = async_to_raw_response_wrapper(
- apps.list,
- )
- self.delete = async_to_raw_response_wrapper(
- apps.delete,
- )
- self.install = async_to_raw_response_wrapper(
- apps.install,
- )
- self.start = async_to_raw_response_wrapper(
- apps.start,
- )
-
-
-class AppsResourceWithStreamingResponse:
- def __init__(self, apps: AppsResource) -> None:
- self._apps = apps
-
- self.list = to_streamed_response_wrapper(
- apps.list,
- )
- self.delete = to_streamed_response_wrapper(
- apps.delete,
- )
- self.install = to_streamed_response_wrapper(
- apps.install,
- )
- self.start = to_streamed_response_wrapper(
- apps.start,
- )
-
-
-class AsyncAppsResourceWithStreamingResponse:
- def __init__(self, apps: AsyncAppsResource) -> None:
- self._apps = apps
-
- self.list = async_to_streamed_response_wrapper(
- apps.list,
- )
- self.delete = async_to_streamed_response_wrapper(
- apps.delete,
- )
- self.install = async_to_streamed_response_wrapper(
- apps.install,
- )
- self.start = async_to_streamed_response_wrapper(
- apps.start,
- )
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
deleted file mode 100644
index 63be619..0000000
--- a/src/mobilerun/resources/devices/devices.py
+++ /dev/null
@@ -1,820 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Literal
-
-import httpx
-
-from .apps import (
- AppsResource,
- AsyncAppsResource,
- AppsResourceWithRawResponse,
- AsyncAppsResourceWithRawResponse,
- AppsResourceWithStreamingResponse,
- AsyncAppsResourceWithStreamingResponse,
-)
-from .state import (
- StateResource,
- AsyncStateResource,
- StateResourceWithRawResponse,
- AsyncStateResourceWithRawResponse,
- StateResourceWithStreamingResponse,
- AsyncStateResourceWithStreamingResponse,
-)
-from .tasks import (
- TasksResource,
- AsyncTasksResource,
- TasksResourceWithRawResponse,
- AsyncTasksResourceWithRawResponse,
- TasksResourceWithStreamingResponse,
- AsyncTasksResourceWithStreamingResponse,
-)
-from ...types import device_list_params, device_create_params
-from .actions import (
- ActionsResource,
- AsyncActionsResource,
- ActionsResourceWithRawResponse,
- AsyncActionsResourceWithRawResponse,
- ActionsResourceWithStreamingResponse,
- AsyncActionsResourceWithStreamingResponse,
-)
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
-from .keyboard import (
- KeyboardResource,
- AsyncKeyboardResource,
- KeyboardResourceWithRawResponse,
- AsyncKeyboardResourceWithRawResponse,
- KeyboardResourceWithStreamingResponse,
- AsyncKeyboardResourceWithStreamingResponse,
-)
-from .packages import (
- PackagesResource,
- AsyncPackagesResource,
- PackagesResourceWithRawResponse,
- AsyncPackagesResourceWithRawResponse,
- PackagesResourceWithStreamingResponse,
- AsyncPackagesResourceWithStreamingResponse,
-)
-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.device import Device
-from ...types.device_list_response import DeviceListResponse
-from ...types.device_count_response import DeviceCountResponse
-
-__all__ = ["DevicesResource", "AsyncDevicesResource"]
-
-
-class DevicesResource(SyncAPIResource):
- @cached_property
- def actions(self) -> ActionsResource:
- return ActionsResource(self._client)
-
- @cached_property
- def state(self) -> StateResource:
- return StateResource(self._client)
-
- @cached_property
- def apps(self) -> AppsResource:
- return AppsResource(self._client)
-
- @cached_property
- def packages(self) -> PackagesResource:
- return PackagesResource(self._client)
-
- @cached_property
- def keyboard(self) -> KeyboardResource:
- return KeyboardResource(self._client)
-
- @cached_property
- def tasks(self) -> TasksResource:
- return TasksResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> DevicesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return DevicesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> DevicesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return DevicesResourceWithStreamingResponse(self)
-
- def create(
- self,
- *,
- device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
- apps: Optional[SequenceNotStr[str]] | Omit = omit,
- country: str | Omit = omit,
- files: Optional[SequenceNotStr[str]] | Omit = omit,
- name: str | Omit = omit,
- proxy: device_create_params.Proxy | Omit = omit,
- # 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,
- ) -> Device:
- """
- Provision a new device
-
- 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
- """
- return self._post(
- "/devices",
- body=maybe_transform(
- {
- "apps": apps,
- "country": country,
- "files": files,
- "name": name,
- "proxy": proxy,
- },
- device_create_params.DeviceCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "device_type": device_type,
- "provider": provider,
- },
- device_create_params.DeviceCreateParams,
- ),
- ),
- cast_to=Device,
- )
-
- def retrieve(
- self,
- device_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,
- ) -> Device:
- """
- Get device info
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return self._get(
- f"/devices/{device_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Device,
- )
-
- def list(
- self,
- *,
- country: str | Omit = omit,
- name: str | Omit = omit,
- order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
- type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- # 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,
- ) -> DeviceListResponse:
- """
- List devices
-
- 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
- """
- return self._get(
- "/devices",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "country": country,
- "name": name,
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- "provider": provider,
- "state": state,
- "type": type,
- },
- device_list_params.DeviceListParams,
- ),
- ),
- cast_to=DeviceListResponse,
- )
-
- def count(
- self,
- *,
- # 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,
- ) -> DeviceCountResponse:
- """Count claimed devices"""
- return self._get(
- "/devices/count",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=DeviceCountResponse,
- )
-
- def terminate(
- self,
- device_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,
- ) -> None:
- """
- Terminate a device
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._delete(
- f"/devices/{device_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def wait_ready(
- self,
- device_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,
- ) -> Device:
- """
- Wait for device to be ready
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return self._get(
- f"/devices/{device_id}/wait",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Device,
- )
-
-
-class AsyncDevicesResource(AsyncAPIResource):
- @cached_property
- def actions(self) -> AsyncActionsResource:
- return AsyncActionsResource(self._client)
-
- @cached_property
- def state(self) -> AsyncStateResource:
- return AsyncStateResource(self._client)
-
- @cached_property
- def apps(self) -> AsyncAppsResource:
- return AsyncAppsResource(self._client)
-
- @cached_property
- def packages(self) -> AsyncPackagesResource:
- return AsyncPackagesResource(self._client)
-
- @cached_property
- def keyboard(self) -> AsyncKeyboardResource:
- return AsyncKeyboardResource(self._client)
-
- @cached_property
- def tasks(self) -> AsyncTasksResource:
- return AsyncTasksResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> AsyncDevicesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncDevicesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncDevicesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncDevicesResourceWithStreamingResponse(self)
-
- async def create(
- self,
- *,
- device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
- apps: Optional[SequenceNotStr[str]] | Omit = omit,
- country: str | Omit = omit,
- files: Optional[SequenceNotStr[str]] | Omit = omit,
- name: str | Omit = omit,
- proxy: device_create_params.Proxy | Omit = omit,
- # 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,
- ) -> Device:
- """
- Provision a new device
-
- 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
- """
- return await self._post(
- "/devices",
- body=await async_maybe_transform(
- {
- "apps": apps,
- "country": country,
- "files": files,
- "name": name,
- "proxy": proxy,
- },
- device_create_params.DeviceCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "device_type": device_type,
- "provider": provider,
- },
- device_create_params.DeviceCreateParams,
- ),
- ),
- cast_to=Device,
- )
-
- async def retrieve(
- self,
- device_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,
- ) -> Device:
- """
- Get device info
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return await self._get(
- f"/devices/{device_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Device,
- )
-
- async def list(
- self,
- *,
- country: str | Omit = omit,
- name: str | Omit = omit,
- order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
- type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- # 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,
- ) -> DeviceListResponse:
- """
- List devices
-
- 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
- """
- return await self._get(
- "/devices",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "country": country,
- "name": name,
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- "provider": provider,
- "state": state,
- "type": type,
- },
- device_list_params.DeviceListParams,
- ),
- ),
- cast_to=DeviceListResponse,
- )
-
- async def count(
- self,
- *,
- # 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,
- ) -> DeviceCountResponse:
- """Count claimed devices"""
- return await self._get(
- "/devices/count",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=DeviceCountResponse,
- )
-
- async def terminate(
- self,
- device_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,
- ) -> None:
- """
- Terminate a device
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._delete(
- f"/devices/{device_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def wait_ready(
- self,
- device_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,
- ) -> Device:
- """
- Wait for device to be ready
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return await self._get(
- f"/devices/{device_id}/wait",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Device,
- )
-
-
-class DevicesResourceWithRawResponse:
- def __init__(self, devices: DevicesResource) -> None:
- self._devices = devices
-
- self.create = to_raw_response_wrapper(
- devices.create,
- )
- self.retrieve = to_raw_response_wrapper(
- devices.retrieve,
- )
- self.list = to_raw_response_wrapper(
- devices.list,
- )
- self.count = to_raw_response_wrapper(
- devices.count,
- )
- self.terminate = to_raw_response_wrapper(
- devices.terminate,
- )
- self.wait_ready = to_raw_response_wrapper(
- devices.wait_ready,
- )
-
- @cached_property
- def actions(self) -> ActionsResourceWithRawResponse:
- return ActionsResourceWithRawResponse(self._devices.actions)
-
- @cached_property
- def state(self) -> StateResourceWithRawResponse:
- return StateResourceWithRawResponse(self._devices.state)
-
- @cached_property
- def apps(self) -> AppsResourceWithRawResponse:
- return AppsResourceWithRawResponse(self._devices.apps)
-
- @cached_property
- def packages(self) -> PackagesResourceWithRawResponse:
- return PackagesResourceWithRawResponse(self._devices.packages)
-
- @cached_property
- def keyboard(self) -> KeyboardResourceWithRawResponse:
- return KeyboardResourceWithRawResponse(self._devices.keyboard)
-
- @cached_property
- def tasks(self) -> TasksResourceWithRawResponse:
- return TasksResourceWithRawResponse(self._devices.tasks)
-
-
-class AsyncDevicesResourceWithRawResponse:
- def __init__(self, devices: AsyncDevicesResource) -> None:
- self._devices = devices
-
- self.create = async_to_raw_response_wrapper(
- devices.create,
- )
- self.retrieve = async_to_raw_response_wrapper(
- devices.retrieve,
- )
- self.list = async_to_raw_response_wrapper(
- devices.list,
- )
- self.count = async_to_raw_response_wrapper(
- devices.count,
- )
- self.terminate = async_to_raw_response_wrapper(
- devices.terminate,
- )
- self.wait_ready = async_to_raw_response_wrapper(
- devices.wait_ready,
- )
-
- @cached_property
- def actions(self) -> AsyncActionsResourceWithRawResponse:
- return AsyncActionsResourceWithRawResponse(self._devices.actions)
-
- @cached_property
- def state(self) -> AsyncStateResourceWithRawResponse:
- return AsyncStateResourceWithRawResponse(self._devices.state)
-
- @cached_property
- def apps(self) -> AsyncAppsResourceWithRawResponse:
- return AsyncAppsResourceWithRawResponse(self._devices.apps)
-
- @cached_property
- def packages(self) -> AsyncPackagesResourceWithRawResponse:
- return AsyncPackagesResourceWithRawResponse(self._devices.packages)
-
- @cached_property
- def keyboard(self) -> AsyncKeyboardResourceWithRawResponse:
- return AsyncKeyboardResourceWithRawResponse(self._devices.keyboard)
-
- @cached_property
- def tasks(self) -> AsyncTasksResourceWithRawResponse:
- return AsyncTasksResourceWithRawResponse(self._devices.tasks)
-
-
-class DevicesResourceWithStreamingResponse:
- def __init__(self, devices: DevicesResource) -> None:
- self._devices = devices
-
- self.create = to_streamed_response_wrapper(
- devices.create,
- )
- self.retrieve = to_streamed_response_wrapper(
- devices.retrieve,
- )
- self.list = to_streamed_response_wrapper(
- devices.list,
- )
- self.count = to_streamed_response_wrapper(
- devices.count,
- )
- self.terminate = to_streamed_response_wrapper(
- devices.terminate,
- )
- self.wait_ready = to_streamed_response_wrapper(
- devices.wait_ready,
- )
-
- @cached_property
- def actions(self) -> ActionsResourceWithStreamingResponse:
- return ActionsResourceWithStreamingResponse(self._devices.actions)
-
- @cached_property
- def state(self) -> StateResourceWithStreamingResponse:
- return StateResourceWithStreamingResponse(self._devices.state)
-
- @cached_property
- def apps(self) -> AppsResourceWithStreamingResponse:
- return AppsResourceWithStreamingResponse(self._devices.apps)
-
- @cached_property
- def packages(self) -> PackagesResourceWithStreamingResponse:
- return PackagesResourceWithStreamingResponse(self._devices.packages)
-
- @cached_property
- def keyboard(self) -> KeyboardResourceWithStreamingResponse:
- return KeyboardResourceWithStreamingResponse(self._devices.keyboard)
-
- @cached_property
- def tasks(self) -> TasksResourceWithStreamingResponse:
- return TasksResourceWithStreamingResponse(self._devices.tasks)
-
-
-class AsyncDevicesResourceWithStreamingResponse:
- def __init__(self, devices: AsyncDevicesResource) -> None:
- self._devices = devices
-
- self.create = async_to_streamed_response_wrapper(
- devices.create,
- )
- self.retrieve = async_to_streamed_response_wrapper(
- devices.retrieve,
- )
- self.list = async_to_streamed_response_wrapper(
- devices.list,
- )
- self.count = async_to_streamed_response_wrapper(
- devices.count,
- )
- self.terminate = async_to_streamed_response_wrapper(
- devices.terminate,
- )
- self.wait_ready = async_to_streamed_response_wrapper(
- devices.wait_ready,
- )
-
- @cached_property
- def actions(self) -> AsyncActionsResourceWithStreamingResponse:
- return AsyncActionsResourceWithStreamingResponse(self._devices.actions)
-
- @cached_property
- def state(self) -> AsyncStateResourceWithStreamingResponse:
- return AsyncStateResourceWithStreamingResponse(self._devices.state)
-
- @cached_property
- def apps(self) -> AsyncAppsResourceWithStreamingResponse:
- return AsyncAppsResourceWithStreamingResponse(self._devices.apps)
-
- @cached_property
- def packages(self) -> AsyncPackagesResourceWithStreamingResponse:
- return AsyncPackagesResourceWithStreamingResponse(self._devices.packages)
-
- @cached_property
- def keyboard(self) -> AsyncKeyboardResourceWithStreamingResponse:
- return AsyncKeyboardResourceWithStreamingResponse(self._devices.keyboard)
-
- @cached_property
- def tasks(self) -> AsyncTasksResourceWithStreamingResponse:
- return AsyncTasksResourceWithStreamingResponse(self._devices.tasks)
diff --git a/src/mobilerun/resources/devices/keyboard.py b/src/mobilerun/resources/devices/keyboard.py
deleted file mode 100644
index 81d8459..0000000
--- a/src/mobilerun/resources/devices/keyboard.py
+++ /dev/null
@@ -1,390 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
-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.devices import keyboard_key_params, keyboard_write_params
-
-__all__ = ["KeyboardResource", "AsyncKeyboardResource"]
-
-
-class KeyboardResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> KeyboardResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return KeyboardResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> KeyboardResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return KeyboardResourceWithStreamingResponse(self)
-
- def clear(
- self,
- device_id: str,
- *,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Clear input
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._delete(
- f"/devices/{device_id}/keyboard",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def key(
- self,
- device_id: str,
- *,
- key: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Input key
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._put(
- f"/devices/{device_id}/keyboard",
- body=maybe_transform({"key": key}, keyboard_key_params.KeyboardKeyParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def write(
- self,
- device_id: str,
- *,
- clear: bool,
- text: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Input text
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._post(
- f"/devices/{device_id}/keyboard",
- body=maybe_transform(
- {
- "clear": clear,
- "text": text,
- },
- keyboard_write_params.KeyboardWriteParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class AsyncKeyboardResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncKeyboardResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncKeyboardResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncKeyboardResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncKeyboardResourceWithStreamingResponse(self)
-
- async def clear(
- self,
- device_id: str,
- *,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Clear input
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._delete(
- f"/devices/{device_id}/keyboard",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def key(
- self,
- device_id: str,
- *,
- key: int,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Input key
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._put(
- f"/devices/{device_id}/keyboard",
- body=await async_maybe_transform({"key": key}, keyboard_key_params.KeyboardKeyParams),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def write(
- self,
- device_id: str,
- *,
- clear: bool,
- text: str,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> None:
- """
- Input text
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._post(
- f"/devices/{device_id}/keyboard",
- body=await async_maybe_transform(
- {
- "clear": clear,
- "text": text,
- },
- keyboard_write_params.KeyboardWriteParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
-
-class KeyboardResourceWithRawResponse:
- def __init__(self, keyboard: KeyboardResource) -> None:
- self._keyboard = keyboard
-
- self.clear = to_raw_response_wrapper(
- keyboard.clear,
- )
- self.key = to_raw_response_wrapper(
- keyboard.key,
- )
- self.write = to_raw_response_wrapper(
- keyboard.write,
- )
-
-
-class AsyncKeyboardResourceWithRawResponse:
- def __init__(self, keyboard: AsyncKeyboardResource) -> None:
- self._keyboard = keyboard
-
- self.clear = async_to_raw_response_wrapper(
- keyboard.clear,
- )
- self.key = async_to_raw_response_wrapper(
- keyboard.key,
- )
- self.write = async_to_raw_response_wrapper(
- keyboard.write,
- )
-
-
-class KeyboardResourceWithStreamingResponse:
- def __init__(self, keyboard: KeyboardResource) -> None:
- self._keyboard = keyboard
-
- self.clear = to_streamed_response_wrapper(
- keyboard.clear,
- )
- self.key = to_streamed_response_wrapper(
- keyboard.key,
- )
- self.write = to_streamed_response_wrapper(
- keyboard.write,
- )
-
-
-class AsyncKeyboardResourceWithStreamingResponse:
- def __init__(self, keyboard: AsyncKeyboardResource) -> None:
- self._keyboard = keyboard
-
- self.clear = async_to_streamed_response_wrapper(
- keyboard.clear,
- )
- self.key = async_to_streamed_response_wrapper(
- keyboard.key,
- )
- self.write = async_to_streamed_response_wrapper(
- keyboard.write,
- )
diff --git a/src/mobilerun/resources/devices/packages.py b/src/mobilerun/resources/devices/packages.py
deleted file mode 100644
index ed3ead4..0000000
--- a/src/mobilerun/resources/devices/packages.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
-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.devices import package_list_params
-from ...types.devices.package_list_response import PackageListResponse
-
-__all__ = ["PackagesResource", "AsyncPackagesResource"]
-
-
-class PackagesResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> PackagesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return PackagesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> PackagesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return PackagesResourceWithStreamingResponse(self)
-
- def list(
- self,
- device_id: str,
- *,
- include_system_packages: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> Optional[PackageListResponse]:
- """
- List packages
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._get(
- f"/devices/{device_id}/packages",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {"include_system_packages": include_system_packages}, package_list_params.PackageListParams
- ),
- ),
- cast_to=PackageListResponse,
- )
-
-
-class AsyncPackagesResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncPackagesResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncPackagesResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncPackagesResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncPackagesResourceWithStreamingResponse(self)
-
- async def list(
- self,
- device_id: str,
- *,
- include_system_packages: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> Optional[PackageListResponse]:
- """
- List packages
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._get(
- f"/devices/{device_id}/packages",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"include_system_packages": include_system_packages}, package_list_params.PackageListParams
- ),
- ),
- cast_to=PackageListResponse,
- )
-
-
-class PackagesResourceWithRawResponse:
- def __init__(self, packages: PackagesResource) -> None:
- self._packages = packages
-
- self.list = to_raw_response_wrapper(
- packages.list,
- )
-
-
-class AsyncPackagesResourceWithRawResponse:
- def __init__(self, packages: AsyncPackagesResource) -> None:
- self._packages = packages
-
- self.list = async_to_raw_response_wrapper(
- packages.list,
- )
-
-
-class PackagesResourceWithStreamingResponse:
- def __init__(self, packages: PackagesResource) -> None:
- self._packages = packages
-
- self.list = to_streamed_response_wrapper(
- packages.list,
- )
-
-
-class AsyncPackagesResourceWithStreamingResponse:
- def __init__(self, packages: AsyncPackagesResource) -> None:
- self._packages = packages
-
- self.list = async_to_streamed_response_wrapper(
- packages.list,
- )
diff --git a/src/mobilerun/resources/devices/state.py b/src/mobilerun/resources/devices/state.py
deleted file mode 100644
index 10521ea..0000000
--- a/src/mobilerun/resources/devices/state.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
-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.devices import state_ui_params, state_screenshot_params
-from ...types.devices.state_ui_response import StateUiResponse
-
-__all__ = ["StateResource", "AsyncStateResource"]
-
-
-class StateResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> StateResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return StateResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> StateResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return StateResourceWithStreamingResponse(self)
-
- def screenshot(
- self,
- device_id: str,
- *,
- hide_overlay: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> str:
- """
- Take screenshot
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._get(
- f"/devices/{device_id}/screenshot",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform({"hide_overlay": hide_overlay}, state_screenshot_params.StateScreenshotParams),
- ),
- cast_to=str,
- )
-
- def time(
- self,
- device_id: str,
- *,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> str:
- """
- Device time
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._get(
- f"/devices/{device_id}/time",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=str,
- )
-
- def ui(
- self,
- device_id: str,
- *,
- filter: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> StateUiResponse:
- """
- UI state
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return self._get(
- f"/devices/{device_id}/ui-state",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform({"filter": filter}, state_ui_params.StateUiParams),
- ),
- cast_to=StateUiResponse,
- )
-
-
-class AsyncStateResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncStateResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncStateResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncStateResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncStateResourceWithStreamingResponse(self)
-
- async def screenshot(
- self,
- device_id: str,
- *,
- hide_overlay: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> str:
- """
- Take screenshot
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._get(
- f"/devices/{device_id}/screenshot",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"hide_overlay": hide_overlay}, state_screenshot_params.StateScreenshotParams
- ),
- ),
- cast_to=str,
- )
-
- async def time(
- self,
- device_id: str,
- *,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> str:
- """
- Device time
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._get(
- f"/devices/{device_id}/time",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=str,
- )
-
- async def ui(
- self,
- device_id: str,
- *,
- filter: bool | Omit = omit,
- x_device_display_id: int | Omit = omit,
- # 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,
- ) -> StateUiResponse:
- """
- UI state
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- extra_headers = {
- **strip_not_given(
- {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
- ),
- **(extra_headers or {}),
- }
- return await self._get(
- f"/devices/{device_id}/ui-state",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform({"filter": filter}, state_ui_params.StateUiParams),
- ),
- cast_to=StateUiResponse,
- )
-
-
-class StateResourceWithRawResponse:
- def __init__(self, state: StateResource) -> None:
- self._state = state
-
- self.screenshot = to_raw_response_wrapper(
- state.screenshot,
- )
- self.time = to_raw_response_wrapper(
- state.time,
- )
- self.ui = to_raw_response_wrapper(
- state.ui,
- )
-
-
-class AsyncStateResourceWithRawResponse:
- def __init__(self, state: AsyncStateResource) -> None:
- self._state = state
-
- self.screenshot = async_to_raw_response_wrapper(
- state.screenshot,
- )
- self.time = async_to_raw_response_wrapper(
- state.time,
- )
- self.ui = async_to_raw_response_wrapper(
- state.ui,
- )
-
-
-class StateResourceWithStreamingResponse:
- def __init__(self, state: StateResource) -> None:
- self._state = state
-
- self.screenshot = to_streamed_response_wrapper(
- state.screenshot,
- )
- self.time = to_streamed_response_wrapper(
- state.time,
- )
- self.ui = to_streamed_response_wrapper(
- state.ui,
- )
-
-
-class AsyncStateResourceWithStreamingResponse:
- def __init__(self, state: AsyncStateResource) -> None:
- self._state = state
-
- self.screenshot = async_to_streamed_response_wrapper(
- state.screenshot,
- )
- self.time = async_to_streamed_response_wrapper(
- state.time,
- )
- self.ui = async_to_streamed_response_wrapper(
- state.ui,
- )
diff --git a/src/mobilerun/resources/devices/tasks.py b/src/mobilerun/resources/devices/tasks.py
deleted file mode 100644
index 69e27f4..0000000
--- a/src/mobilerun/resources/devices/tasks.py
+++ /dev/null
@@ -1,199 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal
-
-import httpx
-
-from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
-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.devices import task_list_params
-from ...types.devices.task_list_response import TaskListResponse
-
-__all__ = ["TasksResource", "AsyncTasksResource"]
-
-
-class TasksResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> TasksResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return TasksResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> TasksResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return TasksResourceWithStreamingResponse(self)
-
- def list(
- self,
- device_id: str,
- *,
- order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # 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,
- ) -> TaskListResponse:
- """
- List tasks for a device
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return self._get(
- f"/devices/{device_id}/tasks",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- },
- task_list_params.TaskListParams,
- ),
- ),
- cast_to=TaskListResponse,
- )
-
-
-class AsyncTasksResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncTasksResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
- """
- return AsyncTasksResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncTasksResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
- """
- return AsyncTasksResourceWithStreamingResponse(self)
-
- async def list(
- self,
- device_id: str,
- *,
- order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # 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,
- ) -> TaskListResponse:
- """
- List tasks for a device
-
- 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 device_id:
- raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
- return await self._get(
- f"/devices/{device_id}/tasks",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- },
- task_list_params.TaskListParams,
- ),
- ),
- cast_to=TaskListResponse,
- )
-
-
-class TasksResourceWithRawResponse:
- def __init__(self, tasks: TasksResource) -> None:
- self._tasks = tasks
-
- self.list = to_raw_response_wrapper(
- tasks.list,
- )
-
-
-class AsyncTasksResourceWithRawResponse:
- def __init__(self, tasks: AsyncTasksResource) -> None:
- self._tasks = tasks
-
- self.list = async_to_raw_response_wrapper(
- tasks.list,
- )
-
-
-class TasksResourceWithStreamingResponse:
- def __init__(self, tasks: TasksResource) -> None:
- self._tasks = tasks
-
- self.list = to_streamed_response_wrapper(
- tasks.list,
- )
-
-
-class AsyncTasksResourceWithStreamingResponse:
- def __init__(self, tasks: AsyncTasksResource) -> None:
- self._tasks = tasks
-
- self.list = async_to_streamed_response_wrapper(
- tasks.list,
- )
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index 72eddf4..48e9ccc 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -3,7 +3,6 @@
from __future__ import annotations
from .task import Task as Task
-from .device import Device as Device
from .llm_model import LlmModel as LlmModel
from .task_status import TaskStatus as TaskStatus
from .app_list_params import AppListParams as AppListParams
@@ -12,15 +11,11 @@
from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
from .task_run_response import TaskRunResponse as TaskRunResponse
-from .device_list_params import DeviceListParams as DeviceListParams
from .hook_list_response import HookListResponse as HookListResponse
from .hook_update_params import HookUpdateParams as HookUpdateParams
from .task_list_response import TaskListResponse as TaskListResponse
from .task_stop_response import TaskStopResponse as TaskStopResponse
-from .device_create_params import DeviceCreateParams as DeviceCreateParams
-from .device_list_response import DeviceListResponse as DeviceListResponse
from .hook_update_response import HookUpdateResponse as HookUpdateResponse
-from .device_count_response import DeviceCountResponse as DeviceCountResponse
from .hook_perform_response import HookPerformResponse as HookPerformResponse
from .hook_subscribe_params import HookSubscribeParams as HookSubscribeParams
from .hook_retrieve_response import HookRetrieveResponse as HookRetrieveResponse
diff --git a/src/mobilerun/types/device.py b/src/mobilerun/types/device.py
deleted file mode 100644
index 3d570c1..0000000
--- a/src/mobilerun/types/device.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from datetime import datetime
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["Device"]
-
-
-class Device(BaseModel):
- id: str
-
- apps: Optional[List[str]] = None
-
- assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None)
-
- country: str
-
- created_at: datetime = FieldInfo(alias="createdAt")
-
- device_type: str = FieldInfo(alias="deviceType")
-
- files: Optional[List[str]] = None
-
- name: str
-
- provider: str
-
- state: str
-
- state_message: str = FieldInfo(alias="stateMessage")
-
- stream_token: str = FieldInfo(alias="streamToken")
-
- stream_url: str = FieldInfo(alias="streamUrl")
-
- task_count: int = FieldInfo(alias="taskCount")
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
-
- user_id: Optional[str] = FieldInfo(alias="userId", default=None)
diff --git a/src/mobilerun/types/device_count_response.py b/src/mobilerun/types/device_count_response.py
deleted file mode 100644
index 517cdeb..0000000
--- a/src/mobilerun/types/device_count_response.py
+++ /dev/null
@@ -1,22 +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__ = ["DeviceCountResponse"]
-
-
-class DeviceCountResponse(BaseModel):
- limrun: int
-
- personal: int
-
- remote: int
-
- roidrun: int
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/device_create_params.py b/src/mobilerun/types/device_create_params.py
deleted file mode 100644
index 4134f5a..0000000
--- a/src/mobilerun/types/device_create_params.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-
-__all__ = ["DeviceCreateParams", "Proxy"]
-
-
-class DeviceCreateParams(TypedDict, total=False):
- device_type: Annotated[
- Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"],
- PropertyInfo(alias="deviceType"),
- ]
-
- provider: Literal["limrun", "remote", "roidrun"]
-
- apps: Optional[SequenceNotStr[str]]
-
- country: str
-
- files: Optional[SequenceNotStr[str]]
-
- name: str
-
- proxy: Proxy
-
-
-class Proxy(TypedDict, total=False):
- host: Required[str]
-
- password: Required[str]
-
- port: Required[int]
-
- user: Required[str]
diff --git a/src/mobilerun/types/device_list_params.py b/src/mobilerun/types/device_list_params.py
deleted file mode 100644
index 48b5c7f..0000000
--- a/src/mobilerun/types/device_list_params.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["DeviceListParams"]
-
-
-class DeviceListParams(TypedDict, total=False):
- country: str
-
- name: str
-
- order_by: Annotated[Literal["id", "createdAt", "updatedAt", "assignedAt"], PropertyInfo(alias="orderBy")]
-
- order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
-
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
-
- provider: Literal["limrun", "personal", "remote", "roidrun"]
-
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"]
-
- type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"]
diff --git a/src/mobilerun/types/device_list_response.py b/src/mobilerun/types/device_list_response.py
deleted file mode 100644
index cd6cc01..0000000
--- a/src/mobilerun/types/device_list_response.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-
-from pydantic import Field as FieldInfo
-
-from .device import Device
-from .._models import BaseModel
-
-__all__ = ["DeviceListResponse", "Pagination"]
-
-
-class Pagination(BaseModel):
- has_next: bool = FieldInfo(alias="hasNext")
-
- has_prev: bool = FieldInfo(alias="hasPrev")
-
- page: int
-
- pages: int
-
- page_size: int = FieldInfo(alias="pageSize")
-
- total: int
-
-
-class DeviceListResponse(BaseModel):
- items: Optional[List[Device]] = None
-
- pagination: Pagination
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/devices/__init__.py b/src/mobilerun/types/devices/__init__.py
index 6bf3b6f..f8ee8b1 100644
--- a/src/mobilerun/types/devices/__init__.py
+++ b/src/mobilerun/types/devices/__init__.py
@@ -1,22 +1,3 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
-
-from .app_list_params import AppListParams as AppListParams
-from .state_ui_params import StateUiParams as StateUiParams
-from .app_start_params import AppStartParams as AppStartParams
-from .task_list_params import TaskListParams as TaskListParams
-from .action_tap_params import ActionTapParams as ActionTapParams
-from .app_list_response import AppListResponse as AppListResponse
-from .state_ui_response import StateUiResponse as StateUiResponse
-from .app_install_params import AppInstallParams as AppInstallParams
-from .task_list_response import TaskListResponse as TaskListResponse
-from .action_swipe_params import ActionSwipeParams as ActionSwipeParams
-from .keyboard_key_params import KeyboardKeyParams as KeyboardKeyParams
-from .package_list_params import PackageListParams as PackageListParams
-from .state_time_response import StateTimeResponse as StateTimeResponse
-from .action_global_params import ActionGlobalParams as ActionGlobalParams
-from .keyboard_write_params import KeyboardWriteParams as KeyboardWriteParams
-from .package_list_response import PackageListResponse as PackageListResponse
-from .state_screenshot_params import StateScreenshotParams as StateScreenshotParams
-from .state_screenshot_response import StateScreenshotResponse as StateScreenshotResponse
diff --git a/src/mobilerun/types/devices/action_global_params.py b/src/mobilerun/types/devices/action_global_params.py
deleted file mode 100644
index a8fca37..0000000
--- a/src/mobilerun/types/devices/action_global_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["ActionGlobalParams"]
-
-
-class ActionGlobalParams(TypedDict, total=False):
- action: Required[int]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/action_swipe_params.py b/src/mobilerun/types/devices/action_swipe_params.py
deleted file mode 100644
index 2f9df10..0000000
--- a/src/mobilerun/types/devices/action_swipe_params.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["ActionSwipeParams"]
-
-
-class ActionSwipeParams(TypedDict, total=False):
- duration: Required[int]
- """Swipe duration in milliseconds"""
-
- end_x: Required[Annotated[int, PropertyInfo(alias="endX")]]
-
- end_y: Required[Annotated[int, PropertyInfo(alias="endY")]]
-
- start_x: Required[Annotated[int, PropertyInfo(alias="startX")]]
-
- start_y: Required[Annotated[int, PropertyInfo(alias="startY")]]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/action_tap_params.py b/src/mobilerun/types/devices/action_tap_params.py
deleted file mode 100644
index 006f57d..0000000
--- a/src/mobilerun/types/devices/action_tap_params.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["ActionTapParams"]
-
-
-class ActionTapParams(TypedDict, total=False):
- x: Required[int]
-
- y: Required[int]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_install_params.py b/src/mobilerun/types/devices/app_install_params.py
deleted file mode 100644
index 915231c..0000000
--- a/src/mobilerun/types/devices/app_install_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["AppInstallParams"]
-
-
-class AppInstallParams(TypedDict, total=False):
- package_name: Required[Annotated[str, PropertyInfo(alias="packageName")]]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_list_params.py b/src/mobilerun/types/devices/app_list_params.py
deleted file mode 100644
index 762be54..0000000
--- a/src/mobilerun/types/devices/app_list_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["AppListParams"]
-
-
-class AppListParams(TypedDict, total=False):
- include_system_apps: Annotated[bool, PropertyInfo(alias="includeSystemApps")]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_list_response.py b/src/mobilerun/types/devices/app_list_response.py
deleted file mode 100644
index c8f8f4e..0000000
--- a/src/mobilerun/types/devices/app_list_response.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-from pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-
-__all__ = ["AppListResponse", "AppListResponseItem"]
-
-
-class AppListResponseItem(BaseModel):
- is_system_app: bool = FieldInfo(alias="isSystemApp")
-
- label: str
-
- package_name: str = FieldInfo(alias="packageName")
-
- version_code: int = FieldInfo(alias="versionCode")
-
- version_name: str = FieldInfo(alias="versionName")
-
-
-AppListResponse: TypeAlias = List[AppListResponseItem]
diff --git a/src/mobilerun/types/devices/app_start_params.py b/src/mobilerun/types/devices/app_start_params.py
deleted file mode 100644
index f5761f1..0000000
--- a/src/mobilerun/types/devices/app_start_params.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["AppStartParams"]
-
-
-class AppStartParams(TypedDict, total=False):
- device_id: Required[Annotated[str, PropertyInfo(alias="deviceId")]]
-
- activity: str
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/keyboard_key_params.py b/src/mobilerun/types/devices/keyboard_key_params.py
deleted file mode 100644
index 85854de..0000000
--- a/src/mobilerun/types/devices/keyboard_key_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["KeyboardKeyParams"]
-
-
-class KeyboardKeyParams(TypedDict, total=False):
- key: Required[int]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/keyboard_write_params.py b/src/mobilerun/types/devices/keyboard_write_params.py
deleted file mode 100644
index 69b8714..0000000
--- a/src/mobilerun/types/devices/keyboard_write_params.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["KeyboardWriteParams"]
-
-
-class KeyboardWriteParams(TypedDict, total=False):
- clear: Required[bool]
-
- text: Required[str]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/package_list_params.py b/src/mobilerun/types/devices/package_list_params.py
deleted file mode 100644
index 450223e..0000000
--- a/src/mobilerun/types/devices/package_list_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["PackageListParams"]
-
-
-class PackageListParams(TypedDict, total=False):
- include_system_packages: Annotated[bool, PropertyInfo(alias="includeSystemPackages")]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/package_list_response.py b/src/mobilerun/types/devices/package_list_response.py
deleted file mode 100644
index 0ab9e4b..0000000
--- a/src/mobilerun/types/devices/package_list_response.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-__all__ = ["PackageListResponse"]
-
-PackageListResponse: TypeAlias = List[str]
diff --git a/src/mobilerun/types/devices/state_screenshot_params.py b/src/mobilerun/types/devices/state_screenshot_params.py
deleted file mode 100644
index fa4d0bd..0000000
--- a/src/mobilerun/types/devices/state_screenshot_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["StateScreenshotParams"]
-
-
-class StateScreenshotParams(TypedDict, total=False):
- hide_overlay: Annotated[bool, PropertyInfo(alias="hideOverlay")]
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/state_screenshot_response.py b/src/mobilerun/types/devices/state_screenshot_response.py
deleted file mode 100644
index aaa4a93..0000000
--- a/src/mobilerun/types/devices/state_screenshot_response.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import TypeAlias
-
-__all__ = ["StateScreenshotResponse"]
-
-StateScreenshotResponse: TypeAlias = str
diff --git a/src/mobilerun/types/devices/state_time_response.py b/src/mobilerun/types/devices/state_time_response.py
deleted file mode 100644
index 6aed1eb..0000000
--- a/src/mobilerun/types/devices/state_time_response.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import TypeAlias
-
-__all__ = ["StateTimeResponse"]
-
-StateTimeResponse: TypeAlias = str
diff --git a/src/mobilerun/types/devices/state_ui_params.py b/src/mobilerun/types/devices/state_ui_params.py
deleted file mode 100644
index de012d2..0000000
--- a/src/mobilerun/types/devices/state_ui_params.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["StateUiParams"]
-
-
-class StateUiParams(TypedDict, total=False):
- filter: bool
-
- x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/state_ui_response.py b/src/mobilerun/types/devices/state_ui_response.py
deleted file mode 100644
index 5254229..0000000
--- a/src/mobilerun/types/devices/state_ui_response.py
+++ /dev/null
@@ -1,91 +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__ = [
- "StateUiResponse",
- "DeviceContext",
- "DeviceContextDisplayMetrics",
- "DeviceContextFilteringParams",
- "DeviceContextScreenBounds",
- "DeviceContextScreenSize",
- "PhoneState",
- "PhoneStateFocusedElement",
-]
-
-
-class DeviceContextDisplayMetrics(BaseModel):
- density: float
-
- density_dpi: int = FieldInfo(alias="densityDpi")
-
- height_pixels: int = FieldInfo(alias="heightPixels")
-
- scaled_density: float = FieldInfo(alias="scaledDensity")
-
- width_pixels: int = FieldInfo(alias="widthPixels")
-
-
-class DeviceContextFilteringParams(BaseModel):
- min_element_size: int
-
- overlay_offset: int
-
-
-class DeviceContextScreenBounds(BaseModel):
- height: int
-
- width: int
-
-
-class DeviceContextScreenSize(BaseModel):
- height: int
-
- width: int
-
-
-class DeviceContext(BaseModel):
- display_metrics: DeviceContextDisplayMetrics
-
- filtering_params: DeviceContextFilteringParams
-
- screen_bounds: DeviceContextScreenBounds
-
- screen_size: DeviceContextScreenSize = FieldInfo(alias="screenSize")
-
-
-class PhoneStateFocusedElement(BaseModel):
- class_name: Optional[str] = FieldInfo(alias="className", default=None)
-
- resource_id: Optional[str] = FieldInfo(alias="resourceId", default=None)
-
- text: Optional[str] = None
-
-
-class PhoneState(BaseModel):
- is_editable: bool = FieldInfo(alias="isEditable")
-
- keyboard_visible: bool = FieldInfo(alias="keyboardVisible")
-
- activity_name: Optional[str] = FieldInfo(alias="activityName", default=None)
-
- current_app: Optional[str] = FieldInfo(alias="currentApp", default=None)
-
- focused_element: Optional[PhoneStateFocusedElement] = FieldInfo(alias="focusedElement", default=None)
-
- package_name: Optional[str] = FieldInfo(alias="packageName", default=None)
-
-
-class StateUiResponse(BaseModel):
- a11y_tree: object
-
- device_context: DeviceContext
-
- phone_state: PhoneState
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/devices/task_list_params.py b/src/mobilerun/types/devices/task_list_params.py
deleted file mode 100644
index 6c98a67..0000000
--- a/src/mobilerun/types/devices/task_list_params.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Literal, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["TaskListParams"]
-
-
-class TaskListParams(TypedDict, total=False):
- order_by: Annotated[Literal["id", "createdAt", "updatedAt", "assignedAt"], PropertyInfo(alias="orderBy")]
-
- order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
-
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun/types/devices/task_list_response.py b/src/mobilerun/types/devices/task_list_response.py
deleted file mode 100644
index a767345..0000000
--- a/src/mobilerun/types/devices/task_list_response.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from datetime import datetime
-
-from pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-
-__all__ = ["TaskListResponse", "Item", "Pagination"]
-
-
-class Item(BaseModel):
- created_at: datetime = FieldInfo(alias="createdAt")
-
- task_id: str = FieldInfo(alias="taskId")
-
- updated_at: datetime = FieldInfo(alias="updatedAt")
-
-
-class Pagination(BaseModel):
- has_next: bool = FieldInfo(alias="hasNext")
-
- has_prev: bool = FieldInfo(alias="hasPrev")
-
- page: int
-
- pages: int
-
- page_size: int = FieldInfo(alias="pageSize")
-
- total: int
-
-
-class TaskListResponse(BaseModel):
- items: Optional[List[Item]] = None
-
- pagination: Pagination
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
diff --git a/tests/api_resources/devices/__init__.py b/tests/api_resources/devices/__init__.py
deleted file mode 100644
index fd8019a..0000000
--- a/tests/api_resources/devices/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/devices/test_actions.py b/tests/api_resources/devices/test_actions.py
deleted file mode 100644
index dec3120..0000000
--- a/tests/api_resources/devices/test_actions.py
+++ /dev/null
@@ -1,408 +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 mobilerun import Mobilerun, AsyncMobilerun
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestActions:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_global(self, client: Mobilerun) -> None:
- action = client.devices.actions.global_(
- device_id="deviceId",
- action=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_global_with_all_params(self, client: Mobilerun) -> None:
- action = client.devices.actions.global_(
- device_id="deviceId",
- action=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_global(self, client: Mobilerun) -> None:
- response = client.devices.actions.with_raw_response.global_(
- device_id="deviceId",
- action=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_global(self, client: Mobilerun) -> None:
- with client.devices.actions.with_streaming_response.global_(
- device_id="deviceId",
- action=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_global(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.actions.with_raw_response.global_(
- device_id="",
- action=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_swipe(self, client: Mobilerun) -> None:
- action = client.devices.actions.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_swipe_with_all_params(self, client: Mobilerun) -> None:
- action = client.devices.actions.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_swipe(self, client: Mobilerun) -> None:
- response = client.devices.actions.with_raw_response.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_swipe(self, client: Mobilerun) -> None:
- with client.devices.actions.with_streaming_response.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_swipe(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.actions.with_raw_response.swipe(
- device_id="",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_tap(self, client: Mobilerun) -> None:
- action = client.devices.actions.tap(
- device_id="deviceId",
- x=0,
- y=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_tap_with_all_params(self, client: Mobilerun) -> None:
- action = client.devices.actions.tap(
- device_id="deviceId",
- x=0,
- y=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_tap(self, client: Mobilerun) -> None:
- response = client.devices.actions.with_raw_response.tap(
- device_id="deviceId",
- x=0,
- y=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_tap(self, client: Mobilerun) -> None:
- with client.devices.actions.with_streaming_response.tap(
- device_id="deviceId",
- x=0,
- y=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_tap(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.actions.with_raw_response.tap(
- device_id="",
- x=0,
- y=0,
- )
-
-
-class TestAsyncActions:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_global(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.global_(
- device_id="deviceId",
- action=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_global_with_all_params(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.global_(
- device_id="deviceId",
- action=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_global(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.actions.with_raw_response.global_(
- device_id="deviceId",
- action=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = await response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_global(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.actions.with_streaming_response.global_(
- device_id="deviceId",
- action=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = await response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_global(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.actions.with_raw_response.global_(
- device_id="",
- action=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_swipe(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_swipe_with_all_params(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_swipe(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.actions.with_raw_response.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = await response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_swipe(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.actions.with_streaming_response.swipe(
- device_id="deviceId",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = await response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_swipe(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.actions.with_raw_response.swipe(
- device_id="",
- duration=10,
- end_x=0,
- end_y=0,
- start_x=0,
- start_y=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_tap(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.tap(
- device_id="deviceId",
- x=0,
- y=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_tap_with_all_params(self, async_client: AsyncMobilerun) -> None:
- action = await async_client.devices.actions.tap(
- device_id="deviceId",
- x=0,
- y=0,
- x_device_display_id=0,
- )
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_tap(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.actions.with_raw_response.tap(
- device_id="deviceId",
- x=0,
- y=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- action = await response.parse()
- assert action is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_tap(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.actions.with_streaming_response.tap(
- device_id="deviceId",
- x=0,
- y=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- action = await response.parse()
- assert action is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_tap(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.actions.with_raw_response.tap(
- device_id="",
- x=0,
- y=0,
- )
diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py
deleted file mode 100644
index 6469d82..0000000
--- a/tests/api_resources/devices/test_apps.py
+++ /dev/null
@@ -1,490 +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, Optional, cast
-
-import pytest
-
-from mobilerun import Mobilerun, AsyncMobilerun
-from tests.utils import assert_matches_type
-from mobilerun.types.devices import AppListResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestApps:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- app = client.devices.apps.list(
- device_id="deviceId",
- )
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- app = client.devices.apps.list(
- device_id="deviceId",
- include_system_apps=True,
- x_device_display_id=0,
- )
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.devices.apps.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = response.parse()
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.devices.apps.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = response.parse()
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_list(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.apps.with_raw_response.list(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_delete(self, client: Mobilerun) -> None:
- app = client.devices.apps.delete(
- package_name="packageName",
- device_id="deviceId",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_delete_with_all_params(self, client: Mobilerun) -> None:
- app = client.devices.apps.delete(
- package_name="packageName",
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_delete(self, client: Mobilerun) -> None:
- response = client.devices.apps.with_raw_response.delete(
- package_name="packageName",
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_delete(self, client: Mobilerun) -> None:
- with client.devices.apps.with_streaming_response.delete(
- package_name="packageName",
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_delete(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.apps.with_raw_response.delete(
- package_name="packageName",
- device_id="",
- )
-
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
- client.devices.apps.with_raw_response.delete(
- package_name="",
- device_id="deviceId",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_install(self, client: Mobilerun) -> None:
- app = client.devices.apps.install(
- device_id="deviceId",
- package_name="packageName",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_install_with_all_params(self, client: Mobilerun) -> None:
- app = client.devices.apps.install(
- device_id="deviceId",
- package_name="packageName",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_install(self, client: Mobilerun) -> None:
- response = client.devices.apps.with_raw_response.install(
- device_id="deviceId",
- package_name="packageName",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_install(self, client: Mobilerun) -> None:
- with client.devices.apps.with_streaming_response.install(
- device_id="deviceId",
- package_name="packageName",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_install(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.apps.with_raw_response.install(
- device_id="",
- package_name="packageName",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_start(self, client: Mobilerun) -> None:
- app = client.devices.apps.start(
- package_name="packageName",
- device_id="deviceId",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_start_with_all_params(self, client: Mobilerun) -> None:
- app = client.devices.apps.start(
- package_name="packageName",
- device_id="deviceId",
- activity="activity",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_start(self, client: Mobilerun) -> None:
- response = client.devices.apps.with_raw_response.start(
- package_name="packageName",
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_start(self, client: Mobilerun) -> None:
- with client.devices.apps.with_streaming_response.start(
- package_name="packageName",
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_start(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.apps.with_raw_response.start(
- package_name="packageName",
- device_id="",
- )
-
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
- client.devices.apps.with_raw_response.start(
- package_name="",
- device_id="deviceId",
- )
-
-
-class TestAsyncApps:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.list(
- device_id="deviceId",
- )
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.list(
- device_id="deviceId",
- include_system_apps=True,
- x_device_display_id=0,
- )
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.apps.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = await response.parse()
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.apps.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = await response.parse()
- assert_matches_type(Optional[AppListResponse], app, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.apps.with_raw_response.list(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_delete(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.delete(
- package_name="packageName",
- device_id="deviceId",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_delete_with_all_params(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.delete(
- package_name="packageName",
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.apps.with_raw_response.delete(
- package_name="packageName",
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = await response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.apps.with_streaming_response.delete(
- package_name="packageName",
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = await response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_delete(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.apps.with_raw_response.delete(
- package_name="packageName",
- device_id="",
- )
-
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
- await async_client.devices.apps.with_raw_response.delete(
- package_name="",
- device_id="deviceId",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_install(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.install(
- device_id="deviceId",
- package_name="packageName",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_install_with_all_params(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.install(
- device_id="deviceId",
- package_name="packageName",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_install(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.apps.with_raw_response.install(
- device_id="deviceId",
- package_name="packageName",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = await response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_install(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.apps.with_streaming_response.install(
- device_id="deviceId",
- package_name="packageName",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = await response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_install(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.apps.with_raw_response.install(
- device_id="",
- package_name="packageName",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_start(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.start(
- package_name="packageName",
- device_id="deviceId",
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_start_with_all_params(self, async_client: AsyncMobilerun) -> None:
- app = await async_client.devices.apps.start(
- package_name="packageName",
- device_id="deviceId",
- activity="activity",
- x_device_display_id=0,
- )
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_start(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.apps.with_raw_response.start(
- package_name="packageName",
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- app = await response.parse()
- assert app is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_start(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.apps.with_streaming_response.start(
- package_name="packageName",
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- app = await response.parse()
- assert app is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_start(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.apps.with_raw_response.start(
- package_name="packageName",
- device_id="",
- )
-
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
- await async_client.devices.apps.with_raw_response.start(
- package_name="",
- device_id="deviceId",
- )
diff --git a/tests/api_resources/devices/test_keyboard.py b/tests/api_resources/devices/test_keyboard.py
deleted file mode 100644
index 0b329c3..0000000
--- a/tests/api_resources/devices/test_keyboard.py
+++ /dev/null
@@ -1,358 +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 mobilerun import Mobilerun, AsyncMobilerun
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestKeyboard:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_clear(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.clear(
- device_id="deviceId",
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_clear_with_all_params(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.clear(
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_clear(self, client: Mobilerun) -> None:
- response = client.devices.keyboard.with_raw_response.clear(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_clear(self, client: Mobilerun) -> None:
- with client.devices.keyboard.with_streaming_response.clear(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_clear(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.keyboard.with_raw_response.clear(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_key(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.key(
- device_id="deviceId",
- key=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_key_with_all_params(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.key(
- device_id="deviceId",
- key=0,
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_key(self, client: Mobilerun) -> None:
- response = client.devices.keyboard.with_raw_response.key(
- device_id="deviceId",
- key=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_key(self, client: Mobilerun) -> None:
- with client.devices.keyboard.with_streaming_response.key(
- device_id="deviceId",
- key=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_key(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.keyboard.with_raw_response.key(
- device_id="",
- key=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_write(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.write(
- device_id="deviceId",
- clear=True,
- text="text",
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_write_with_all_params(self, client: Mobilerun) -> None:
- keyboard = client.devices.keyboard.write(
- device_id="deviceId",
- clear=True,
- text="text",
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_write(self, client: Mobilerun) -> None:
- response = client.devices.keyboard.with_raw_response.write(
- device_id="deviceId",
- clear=True,
- text="text",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_write(self, client: Mobilerun) -> None:
- with client.devices.keyboard.with_streaming_response.write(
- device_id="deviceId",
- clear=True,
- text="text",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_write(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.keyboard.with_raw_response.write(
- device_id="",
- clear=True,
- text="text",
- )
-
-
-class TestAsyncKeyboard:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_clear(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.clear(
- device_id="deviceId",
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_clear_with_all_params(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.clear(
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_clear(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.keyboard.with_raw_response.clear(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = await response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_clear(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.keyboard.with_streaming_response.clear(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = await response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_clear(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.keyboard.with_raw_response.clear(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_key(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.key(
- device_id="deviceId",
- key=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_key_with_all_params(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.key(
- device_id="deviceId",
- key=0,
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_key(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.keyboard.with_raw_response.key(
- device_id="deviceId",
- key=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = await response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_key(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.keyboard.with_streaming_response.key(
- device_id="deviceId",
- key=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = await response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_key(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.keyboard.with_raw_response.key(
- device_id="",
- key=0,
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_write(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.write(
- device_id="deviceId",
- clear=True,
- text="text",
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_write_with_all_params(self, async_client: AsyncMobilerun) -> None:
- keyboard = await async_client.devices.keyboard.write(
- device_id="deviceId",
- clear=True,
- text="text",
- x_device_display_id=0,
- )
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_write(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.keyboard.with_raw_response.write(
- device_id="deviceId",
- clear=True,
- text="text",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- keyboard = await response.parse()
- assert keyboard is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_write(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.keyboard.with_streaming_response.write(
- device_id="deviceId",
- clear=True,
- text="text",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- keyboard = await response.parse()
- assert keyboard is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_write(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.keyboard.with_raw_response.write(
- device_id="",
- clear=True,
- text="text",
- )
diff --git a/tests/api_resources/devices/test_packages.py b/tests/api_resources/devices/test_packages.py
deleted file mode 100644
index 1a02296..0000000
--- a/tests/api_resources/devices/test_packages.py
+++ /dev/null
@@ -1,128 +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, Optional, cast
-
-import pytest
-
-from mobilerun import Mobilerun, AsyncMobilerun
-from tests.utils import assert_matches_type
-from mobilerun.types.devices import PackageListResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestPackages:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- package = client.devices.packages.list(
- device_id="deviceId",
- )
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- package = client.devices.packages.list(
- device_id="deviceId",
- include_system_packages=True,
- x_device_display_id=0,
- )
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.devices.packages.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- package = response.parse()
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.devices.packages.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- package = response.parse()
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_list(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.packages.with_raw_response.list(
- device_id="",
- )
-
-
-class TestAsyncPackages:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- package = await async_client.devices.packages.list(
- device_id="deviceId",
- )
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- package = await async_client.devices.packages.list(
- device_id="deviceId",
- include_system_packages=True,
- x_device_display_id=0,
- )
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.packages.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- package = await response.parse()
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.packages.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- package = await response.parse()
- assert_matches_type(Optional[PackageListResponse], package, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.packages.with_raw_response.list(
- device_id="",
- )
diff --git a/tests/api_resources/devices/test_state.py b/tests/api_resources/devices/test_state.py
deleted file mode 100644
index 27879b7..0000000
--- a/tests/api_resources/devices/test_state.py
+++ /dev/null
@@ -1,336 +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 mobilerun import Mobilerun, AsyncMobilerun
-from tests.utils import assert_matches_type
-from mobilerun.types.devices import (
- StateUiResponse,
-)
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestState:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_screenshot(self, client: Mobilerun) -> None:
- state = client.devices.state.screenshot(
- device_id="deviceId",
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_screenshot_with_all_params(self, client: Mobilerun) -> None:
- state = client.devices.state.screenshot(
- device_id="deviceId",
- hide_overlay=True,
- x_device_display_id=0,
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_screenshot(self, client: Mobilerun) -> None:
- response = client.devices.state.with_raw_response.screenshot(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = response.parse()
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_screenshot(self, client: Mobilerun) -> None:
- with client.devices.state.with_streaming_response.screenshot(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = response.parse()
- assert_matches_type(str, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_screenshot(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.state.with_raw_response.screenshot(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_time(self, client: Mobilerun) -> None:
- state = client.devices.state.time(
- device_id="deviceId",
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_time_with_all_params(self, client: Mobilerun) -> None:
- state = client.devices.state.time(
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_time(self, client: Mobilerun) -> None:
- response = client.devices.state.with_raw_response.time(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = response.parse()
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_time(self, client: Mobilerun) -> None:
- with client.devices.state.with_streaming_response.time(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = response.parse()
- assert_matches_type(str, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_time(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.state.with_raw_response.time(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_ui(self, client: Mobilerun) -> None:
- state = client.devices.state.ui(
- device_id="deviceId",
- )
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_ui_with_all_params(self, client: Mobilerun) -> None:
- state = client.devices.state.ui(
- device_id="deviceId",
- filter=True,
- x_device_display_id=0,
- )
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_ui(self, client: Mobilerun) -> None:
- response = client.devices.state.with_raw_response.ui(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = response.parse()
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_ui(self, client: Mobilerun) -> None:
- with client.devices.state.with_streaming_response.ui(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = response.parse()
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_ui(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.state.with_raw_response.ui(
- device_id="",
- )
-
-
-class TestAsyncState:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_screenshot(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.screenshot(
- device_id="deviceId",
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_screenshot_with_all_params(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.screenshot(
- device_id="deviceId",
- hide_overlay=True,
- x_device_display_id=0,
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_screenshot(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.state.with_raw_response.screenshot(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = await response.parse()
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_screenshot(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.state.with_streaming_response.screenshot(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = await response.parse()
- assert_matches_type(str, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_screenshot(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.state.with_raw_response.screenshot(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_time(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.time(
- device_id="deviceId",
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_time_with_all_params(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.time(
- device_id="deviceId",
- x_device_display_id=0,
- )
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_time(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.state.with_raw_response.time(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = await response.parse()
- assert_matches_type(str, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_time(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.state.with_streaming_response.time(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = await response.parse()
- assert_matches_type(str, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_time(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.state.with_raw_response.time(
- device_id="",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_ui(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.ui(
- device_id="deviceId",
- )
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_ui_with_all_params(self, async_client: AsyncMobilerun) -> None:
- state = await async_client.devices.state.ui(
- device_id="deviceId",
- filter=True,
- x_device_display_id=0,
- )
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_ui(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.state.with_raw_response.ui(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- state = await response.parse()
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_ui(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.state.with_streaming_response.ui(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- state = await response.parse()
- assert_matches_type(StateUiResponse, state, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_ui(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.state.with_raw_response.ui(
- device_id="",
- )
diff --git a/tests/api_resources/devices/test_tasks.py b/tests/api_resources/devices/test_tasks.py
deleted file mode 100644
index 0b41b32..0000000
--- a/tests/api_resources/devices/test_tasks.py
+++ /dev/null
@@ -1,132 +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 mobilerun import Mobilerun, AsyncMobilerun
-from tests.utils import assert_matches_type
-from mobilerun.types.devices import TaskListResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestTasks:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- task = client.devices.tasks.list(
- device_id="deviceId",
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- task = client.devices.tasks.list(
- device_id="deviceId",
- order_by="id",
- order_by_direction="asc",
- page=0,
- page_size=0,
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.devices.tasks.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.devices.tasks.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_list(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.tasks.with_raw_response.list(
- device_id="",
- )
-
-
-class TestAsyncTasks:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.devices.tasks.list(
- device_id="deviceId",
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.devices.tasks.list(
- device_id="deviceId",
- order_by="id",
- order_by_direction="asc",
- page=0,
- page_size=0,
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.tasks.with_raw_response.list(
- device_id="deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = await response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.tasks.with_streaming_response.list(
- device_id="deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = await response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.tasks.with_raw_response.list(
- device_id="",
- )
diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py
deleted file mode 100644
index f762064..0000000
--- a/tests/api_resources/test_devices.py
+++ /dev/null
@@ -1,514 +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 mobilerun import Mobilerun, AsyncMobilerun
-from tests.utils import assert_matches_type
-from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestDevices:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_create(self, client: Mobilerun) -> None:
- device = client.devices.create()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Mobilerun) -> None:
- device = client.devices.create(
- device_type="device_slot",
- provider="limrun",
- apps=["string"],
- country="country",
- files=["string"],
- name="name",
- proxy={
- "host": "host",
- "password": "password",
- "port": 0,
- "user": "user",
- },
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_retrieve(self, client: Mobilerun) -> None:
- device = client.devices.retrieve(
- "deviceId",
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_retrieve(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.retrieve(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_retrieve(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.retrieve(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_retrieve(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- device = client.devices.list()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- device = client.devices.list(
- country="country",
- name="name",
- order_by="id",
- order_by_direction="asc",
- page=0,
- page_size=0,
- provider="limrun",
- state="creating",
- type="device_slot",
- )
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_count(self, client: Mobilerun) -> None:
- device = client.devices.count()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_count(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.count()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_count(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.count() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_terminate(self, client: Mobilerun) -> None:
- device = client.devices.terminate(
- "deviceId",
- )
- assert device is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_terminate(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.terminate(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert device is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_terminate(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.terminate(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert device is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_terminate(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.with_raw_response.terminate(
- "",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_wait_ready(self, client: Mobilerun) -> None:
- device = client.devices.wait_ready(
- "deviceId",
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_wait_ready(self, client: Mobilerun) -> None:
- response = client.devices.with_raw_response.wait_ready(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_wait_ready(self, client: Mobilerun) -> None:
- with client.devices.with_streaming_response.wait_ready(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_path_params_wait_ready(self, client: Mobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- client.devices.with_raw_response.wait_ready(
- "",
- )
-
-
-class TestAsyncDevices:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_create(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.create()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.create(
- device_type="device_slot",
- provider="limrun",
- apps=["string"],
- country="country",
- files=["string"],
- name="name",
- proxy={
- "host": "host",
- "password": "password",
- "port": 0,
- "user": "user",
- },
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.retrieve(
- "deviceId",
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.retrieve(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.retrieve(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.list()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.list(
- country="country",
- name="name",
- order_by="id",
- order_by_direction="asc",
- page=0,
- page_size=0,
- provider="limrun",
- state="creating",
- type="device_slot",
- )
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert_matches_type(DeviceListResponse, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_count(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.count()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_count(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.count()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_count(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.count() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert_matches_type(DeviceCountResponse, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_terminate(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.terminate(
- "deviceId",
- )
- assert device is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_terminate(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.terminate(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert device is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_terminate(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.terminate(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert device is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_terminate(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.with_raw_response.terminate(
- "",
- )
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_wait_ready(self, async_client: AsyncMobilerun) -> None:
- device = await async_client.devices.wait_ready(
- "deviceId",
- )
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_wait_ready(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.devices.with_raw_response.wait_ready(
- "deviceId",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_wait_ready(self, async_client: AsyncMobilerun) -> None:
- async with async_client.devices.with_streaming_response.wait_ready(
- "deviceId",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- device = await response.parse()
- assert_matches_type(Device, device, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_path_params_wait_ready(self, async_client: AsyncMobilerun) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
- await async_client.devices.with_raw_response.wait_ready(
- "",
- )
From 866c20ec6ebd177c861777fee900259186347ef0 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 14 Jan 2026 14:53:37 +0000
Subject: [PATCH 04/25] feat(api): api update
---
.stats.yml | 6 +-
README.md | 20 +
api.md | 86 ++
src/mobilerun/_client.py | 39 +-
src/mobilerun/resources/__init__.py | 14 +
src/mobilerun/resources/devices/__init__.py | 103 +++
src/mobilerun/resources/devices/actions.py | 424 +++++++++
src/mobilerun/resources/devices/apps.py | 495 +++++++++++
src/mobilerun/resources/devices/devices.py | 820 ++++++++++++++++++
src/mobilerun/resources/devices/keyboard.py | 390 +++++++++
src/mobilerun/resources/devices/packages.py | 195 +++++
src/mobilerun/resources/devices/state.py | 385 ++++++++
src/mobilerun/resources/devices/tasks.py | 199 +++++
src/mobilerun/types/__init__.py | 5 +
src/mobilerun/types/device.py | 47 +
src/mobilerun/types/device_count_response.py | 22 +
src/mobilerun/types/device_create_params.py | 40 +
src/mobilerun/types/device_list_params.py | 29 +
src/mobilerun/types/device_list_response.py | 33 +
src/mobilerun/types/devices/__init__.py | 19 +
.../types/devices/action_global_params.py | 15 +
.../types/devices/action_swipe_params.py | 24 +
.../types/devices/action_tap_params.py | 17 +
.../types/devices/app_install_params.py | 15 +
.../types/devices/app_list_params.py | 15 +
.../types/devices/app_list_response.py | 25 +
.../types/devices/app_start_params.py | 17 +
.../types/devices/keyboard_key_params.py | 15 +
.../types/devices/keyboard_write_params.py | 17 +
.../types/devices/package_list_params.py | 15 +
.../types/devices/package_list_response.py | 8 +
.../types/devices/state_screenshot_params.py | 15 +
.../devices/state_screenshot_response.py | 7 +
.../types/devices/state_time_response.py | 7 +
.../types/devices/state_ui_params.py | 15 +
.../types/devices/state_ui_response.py | 91 ++
.../types/devices/task_list_params.py | 19 +
.../types/devices/task_list_response.py | 41 +
tests/api_resources/devices/__init__.py | 1 +
tests/api_resources/devices/test_actions.py | 408 +++++++++
tests/api_resources/devices/test_apps.py | 490 +++++++++++
tests/api_resources/devices/test_keyboard.py | 358 ++++++++
tests/api_resources/devices/test_packages.py | 128 +++
tests/api_resources/devices/test_state.py | 336 +++++++
tests/api_resources/devices/test_tasks.py | 132 +++
tests/api_resources/test_devices.py | 514 +++++++++++
46 files changed, 6112 insertions(+), 4 deletions(-)
create mode 100644 src/mobilerun/resources/devices/__init__.py
create mode 100644 src/mobilerun/resources/devices/actions.py
create mode 100644 src/mobilerun/resources/devices/apps.py
create mode 100644 src/mobilerun/resources/devices/devices.py
create mode 100644 src/mobilerun/resources/devices/keyboard.py
create mode 100644 src/mobilerun/resources/devices/packages.py
create mode 100644 src/mobilerun/resources/devices/state.py
create mode 100644 src/mobilerun/resources/devices/tasks.py
create mode 100644 src/mobilerun/types/device.py
create mode 100644 src/mobilerun/types/device_count_response.py
create mode 100644 src/mobilerun/types/device_create_params.py
create mode 100644 src/mobilerun/types/device_list_params.py
create mode 100644 src/mobilerun/types/device_list_response.py
create mode 100644 src/mobilerun/types/devices/action_global_params.py
create mode 100644 src/mobilerun/types/devices/action_swipe_params.py
create mode 100644 src/mobilerun/types/devices/action_tap_params.py
create mode 100644 src/mobilerun/types/devices/app_install_params.py
create mode 100644 src/mobilerun/types/devices/app_list_params.py
create mode 100644 src/mobilerun/types/devices/app_list_response.py
create mode 100644 src/mobilerun/types/devices/app_start_params.py
create mode 100644 src/mobilerun/types/devices/keyboard_key_params.py
create mode 100644 src/mobilerun/types/devices/keyboard_write_params.py
create mode 100644 src/mobilerun/types/devices/package_list_params.py
create mode 100644 src/mobilerun/types/devices/package_list_response.py
create mode 100644 src/mobilerun/types/devices/state_screenshot_params.py
create mode 100644 src/mobilerun/types/devices/state_screenshot_response.py
create mode 100644 src/mobilerun/types/devices/state_time_response.py
create mode 100644 src/mobilerun/types/devices/state_ui_params.py
create mode 100644 src/mobilerun/types/devices/state_ui_response.py
create mode 100644 src/mobilerun/types/devices/task_list_params.py
create mode 100644 src/mobilerun/types/devices/task_list_response.py
create mode 100644 tests/api_resources/devices/__init__.py
create mode 100644 tests/api_resources/devices/test_actions.py
create mode 100644 tests/api_resources/devices/test_apps.py
create mode 100644 tests/api_resources/devices/test_keyboard.py
create mode 100644 tests/api_resources/devices/test_packages.py
create mode 100644 tests/api_resources/devices/test_state.py
create mode 100644 tests/api_resources/devices/test_tasks.py
create mode 100644 tests/api_resources/test_devices.py
diff --git a/.stats.yml b/.stats.yml
index d703f41..abeefba 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 29
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-9bc196694afd948cfd36c21c4779815df718b41928ded5b93760f4d6afa853ef.yml
-openapi_spec_hash: dd56ae43482890faf056c390294ecff5
+configured_endpoints: 50
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-b3dca99ca43851c1e9adbb78ad6a8a5841cf0b559bf66663c947c41e8635901e.yml
+openapi_spec_hash: 50964e3f8e40873dcb0a768a7fdf855d
config_hash: d1f61f26938ee3af50fa5f703318307d
diff --git a/README.md b/README.md
index 84c1f14..0eece63 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,26 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
+## Nested params
+
+Nested parameters are dictionaries, typed using `TypedDict`, for example:
+
+```python
+from mobilerun import Mobilerun
+
+client = Mobilerun()
+
+device = client.devices.create(
+ proxy={
+ "host": "host",
+ "password": "password",
+ "port": 0,
+ "user": "user",
+ },
+)
+print(device.proxy)
+```
+
## Handling errors
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `mobilerun.APIConnectionError` is raised.
diff --git a/api.md b/api.md
index f518023..0d58a6a 100644
--- a/api.md
+++ b/api.md
@@ -54,6 +54,92 @@ Methods:
- client.tasks.ui_states.retrieve(index, \*, task_id) -> MediaResponse
- client.tasks.ui_states.list(task_id) -> UiStateListResponse
+# Devices
+
+Types:
+
+```python
+from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
+```
+
+Methods:
+
+- client.devices.create(\*\*params) -> Device
+- client.devices.retrieve(device_id) -> Device
+- client.devices.list(\*\*params) -> DeviceListResponse
+- client.devices.count() -> DeviceCountResponse
+- client.devices.terminate(device_id) -> None
+- client.devices.wait_ready(device_id) -> Device
+
+## Actions
+
+Methods:
+
+- client.devices.actions.global\_(device_id, \*\*params) -> None
+- client.devices.actions.swipe(device_id, \*\*params) -> None
+- client.devices.actions.tap(device_id, \*\*params) -> None
+
+## State
+
+Types:
+
+```python
+from mobilerun.types.devices import StateScreenshotResponse, StateTimeResponse, StateUiResponse
+```
+
+Methods:
+
+- client.devices.state.screenshot(device_id, \*\*params) -> str
+- client.devices.state.time(device_id) -> str
+- client.devices.state.ui(device_id, \*\*params) -> StateUiResponse
+
+## Apps
+
+Types:
+
+```python
+from mobilerun.types.devices import AppListResponse
+```
+
+Methods:
+
+- client.devices.apps.list(device_id, \*\*params) -> Optional[AppListResponse]
+- client.devices.apps.delete(package_name, \*, device_id) -> None
+- client.devices.apps.install(device_id, \*\*params) -> None
+- client.devices.apps.start(package_name, \*, device_id, \*\*params) -> None
+
+## Packages
+
+Types:
+
+```python
+from mobilerun.types.devices import PackageListResponse
+```
+
+Methods:
+
+- client.devices.packages.list(device_id, \*\*params) -> Optional[PackageListResponse]
+
+## Keyboard
+
+Methods:
+
+- client.devices.keyboard.clear(device_id) -> None
+- client.devices.keyboard.key(device_id, \*\*params) -> None
+- client.devices.keyboard.write(device_id, \*\*params) -> None
+
+## Tasks
+
+Types:
+
+```python
+from mobilerun.types.devices import TaskListResponse
+```
+
+Methods:
+
+- client.devices.tasks.list(device_id, \*\*params) -> TaskListResponse
+
# Apps
Types:
diff --git a/src/mobilerun/_client.py b/src/mobilerun/_client.py
index 271bb95..dd728b1 100644
--- a/src/mobilerun/_client.py
+++ b/src/mobilerun/_client.py
@@ -32,10 +32,11 @@
)
if TYPE_CHECKING:
- from .resources import apps, hooks, tasks, credentials
+ from .resources import apps, hooks, tasks, devices, credentials
from .resources.apps import AppsResource, AsyncAppsResource
from .resources.hooks import HooksResource, AsyncHooksResource
from .resources.tasks.tasks import TasksResource, AsyncTasksResource
+ from .resources.devices.devices import DevicesResource, AsyncDevicesResource
from .resources.credentials.credentials import CredentialsResource, AsyncCredentialsResource
__all__ = [
@@ -107,6 +108,12 @@ def tasks(self) -> TasksResource:
return TasksResource(self)
+ @cached_property
+ def devices(self) -> DevicesResource:
+ from .resources.devices import DevicesResource
+
+ return DevicesResource(self)
+
@cached_property
def apps(self) -> AppsResource:
from .resources.apps import AppsResource
@@ -306,6 +313,12 @@ def tasks(self) -> AsyncTasksResource:
return AsyncTasksResource(self)
+ @cached_property
+ def devices(self) -> AsyncDevicesResource:
+ from .resources.devices import AsyncDevicesResource
+
+ return AsyncDevicesResource(self)
+
@cached_property
def apps(self) -> AsyncAppsResource:
from .resources.apps import AsyncAppsResource
@@ -460,6 +473,12 @@ def tasks(self) -> tasks.TasksResourceWithRawResponse:
return TasksResourceWithRawResponse(self._client.tasks)
+ @cached_property
+ def devices(self) -> devices.DevicesResourceWithRawResponse:
+ from .resources.devices import DevicesResourceWithRawResponse
+
+ return DevicesResourceWithRawResponse(self._client.devices)
+
@cached_property
def apps(self) -> apps.AppsResourceWithRawResponse:
from .resources.apps import AppsResourceWithRawResponse
@@ -491,6 +510,12 @@ def tasks(self) -> tasks.AsyncTasksResourceWithRawResponse:
return AsyncTasksResourceWithRawResponse(self._client.tasks)
+ @cached_property
+ def devices(self) -> devices.AsyncDevicesResourceWithRawResponse:
+ from .resources.devices import AsyncDevicesResourceWithRawResponse
+
+ return AsyncDevicesResourceWithRawResponse(self._client.devices)
+
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithRawResponse:
from .resources.apps import AsyncAppsResourceWithRawResponse
@@ -522,6 +547,12 @@ def tasks(self) -> tasks.TasksResourceWithStreamingResponse:
return TasksResourceWithStreamingResponse(self._client.tasks)
+ @cached_property
+ def devices(self) -> devices.DevicesResourceWithStreamingResponse:
+ from .resources.devices import DevicesResourceWithStreamingResponse
+
+ return DevicesResourceWithStreamingResponse(self._client.devices)
+
@cached_property
def apps(self) -> apps.AppsResourceWithStreamingResponse:
from .resources.apps import AppsResourceWithStreamingResponse
@@ -553,6 +584,12 @@ def tasks(self) -> tasks.AsyncTasksResourceWithStreamingResponse:
return AsyncTasksResourceWithStreamingResponse(self._client.tasks)
+ @cached_property
+ def devices(self) -> devices.AsyncDevicesResourceWithStreamingResponse:
+ from .resources.devices import AsyncDevicesResourceWithStreamingResponse
+
+ return AsyncDevicesResourceWithStreamingResponse(self._client.devices)
+
@cached_property
def apps(self) -> apps.AsyncAppsResourceWithStreamingResponse:
from .resources.apps import AsyncAppsResourceWithStreamingResponse
diff --git a/src/mobilerun/resources/__init__.py b/src/mobilerun/resources/__init__.py
index 9204f81..c65175f 100644
--- a/src/mobilerun/resources/__init__.py
+++ b/src/mobilerun/resources/__init__.py
@@ -24,6 +24,14 @@
TasksResourceWithStreamingResponse,
AsyncTasksResourceWithStreamingResponse,
)
+from .devices import (
+ DevicesResource,
+ AsyncDevicesResource,
+ DevicesResourceWithRawResponse,
+ AsyncDevicesResourceWithRawResponse,
+ DevicesResourceWithStreamingResponse,
+ AsyncDevicesResourceWithStreamingResponse,
+)
from .credentials import (
CredentialsResource,
AsyncCredentialsResource,
@@ -40,6 +48,12 @@
"AsyncTasksResourceWithRawResponse",
"TasksResourceWithStreamingResponse",
"AsyncTasksResourceWithStreamingResponse",
+ "DevicesResource",
+ "AsyncDevicesResource",
+ "DevicesResourceWithRawResponse",
+ "AsyncDevicesResourceWithRawResponse",
+ "DevicesResourceWithStreamingResponse",
+ "AsyncDevicesResourceWithStreamingResponse",
"AppsResource",
"AsyncAppsResource",
"AppsResourceWithRawResponse",
diff --git a/src/mobilerun/resources/devices/__init__.py b/src/mobilerun/resources/devices/__init__.py
new file mode 100644
index 0000000..db9559e
--- /dev/null
+++ b/src/mobilerun/resources/devices/__init__.py
@@ -0,0 +1,103 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .apps import (
+ AppsResource,
+ AsyncAppsResource,
+ AppsResourceWithRawResponse,
+ AsyncAppsResourceWithRawResponse,
+ AppsResourceWithStreamingResponse,
+ AsyncAppsResourceWithStreamingResponse,
+)
+from .state import (
+ StateResource,
+ AsyncStateResource,
+ StateResourceWithRawResponse,
+ AsyncStateResourceWithRawResponse,
+ StateResourceWithStreamingResponse,
+ AsyncStateResourceWithStreamingResponse,
+)
+from .tasks import (
+ TasksResource,
+ AsyncTasksResource,
+ TasksResourceWithRawResponse,
+ AsyncTasksResourceWithRawResponse,
+ TasksResourceWithStreamingResponse,
+ AsyncTasksResourceWithStreamingResponse,
+)
+from .actions import (
+ ActionsResource,
+ AsyncActionsResource,
+ ActionsResourceWithRawResponse,
+ AsyncActionsResourceWithRawResponse,
+ ActionsResourceWithStreamingResponse,
+ AsyncActionsResourceWithStreamingResponse,
+)
+from .devices import (
+ DevicesResource,
+ AsyncDevicesResource,
+ DevicesResourceWithRawResponse,
+ AsyncDevicesResourceWithRawResponse,
+ DevicesResourceWithStreamingResponse,
+ AsyncDevicesResourceWithStreamingResponse,
+)
+from .keyboard import (
+ KeyboardResource,
+ AsyncKeyboardResource,
+ KeyboardResourceWithRawResponse,
+ AsyncKeyboardResourceWithRawResponse,
+ KeyboardResourceWithStreamingResponse,
+ AsyncKeyboardResourceWithStreamingResponse,
+)
+from .packages import (
+ PackagesResource,
+ AsyncPackagesResource,
+ PackagesResourceWithRawResponse,
+ AsyncPackagesResourceWithRawResponse,
+ PackagesResourceWithStreamingResponse,
+ AsyncPackagesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "ActionsResource",
+ "AsyncActionsResource",
+ "ActionsResourceWithRawResponse",
+ "AsyncActionsResourceWithRawResponse",
+ "ActionsResourceWithStreamingResponse",
+ "AsyncActionsResourceWithStreamingResponse",
+ "StateResource",
+ "AsyncStateResource",
+ "StateResourceWithRawResponse",
+ "AsyncStateResourceWithRawResponse",
+ "StateResourceWithStreamingResponse",
+ "AsyncStateResourceWithStreamingResponse",
+ "AppsResource",
+ "AsyncAppsResource",
+ "AppsResourceWithRawResponse",
+ "AsyncAppsResourceWithRawResponse",
+ "AppsResourceWithStreamingResponse",
+ "AsyncAppsResourceWithStreamingResponse",
+ "PackagesResource",
+ "AsyncPackagesResource",
+ "PackagesResourceWithRawResponse",
+ "AsyncPackagesResourceWithRawResponse",
+ "PackagesResourceWithStreamingResponse",
+ "AsyncPackagesResourceWithStreamingResponse",
+ "KeyboardResource",
+ "AsyncKeyboardResource",
+ "KeyboardResourceWithRawResponse",
+ "AsyncKeyboardResourceWithRawResponse",
+ "KeyboardResourceWithStreamingResponse",
+ "AsyncKeyboardResourceWithStreamingResponse",
+ "TasksResource",
+ "AsyncTasksResource",
+ "TasksResourceWithRawResponse",
+ "AsyncTasksResourceWithRawResponse",
+ "TasksResourceWithStreamingResponse",
+ "AsyncTasksResourceWithStreamingResponse",
+ "DevicesResource",
+ "AsyncDevicesResource",
+ "DevicesResourceWithRawResponse",
+ "AsyncDevicesResourceWithRawResponse",
+ "DevicesResourceWithStreamingResponse",
+ "AsyncDevicesResourceWithStreamingResponse",
+]
diff --git a/src/mobilerun/resources/devices/actions.py b/src/mobilerun/resources/devices/actions.py
new file mode 100644
index 0000000..b0e404a
--- /dev/null
+++ b/src/mobilerun/resources/devices/actions.py
@@ -0,0 +1,424 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
+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.devices import action_tap_params, action_swipe_params, action_global_params
+
+__all__ = ["ActionsResource", "AsyncActionsResource"]
+
+
+class ActionsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ActionsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return ActionsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ActionsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return ActionsResourceWithStreamingResponse(self)
+
+ def global_(
+ self,
+ device_id: str,
+ *,
+ action: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Perform a global action
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ f"/devices/{device_id}/global",
+ body=maybe_transform({"action": action}, action_global_params.ActionGlobalParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def swipe(
+ self,
+ device_id: str,
+ *,
+ duration: int,
+ end_x: int,
+ end_y: int,
+ start_x: int,
+ start_y: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Swipe
+
+ Args:
+ duration: Swipe duration in milliseconds
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ f"/devices/{device_id}/swipe",
+ body=maybe_transform(
+ {
+ "duration": duration,
+ "end_x": end_x,
+ "end_y": end_y,
+ "start_x": start_x,
+ "start_y": start_y,
+ },
+ action_swipe_params.ActionSwipeParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def tap(
+ self,
+ device_id: str,
+ *,
+ x: int,
+ y: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Tap by coordinates
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ f"/devices/{device_id}/tap",
+ body=maybe_transform(
+ {
+ "x": x,
+ "y": y,
+ },
+ action_tap_params.ActionTapParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncActionsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncActionsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncActionsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncActionsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncActionsResourceWithStreamingResponse(self)
+
+ async def global_(
+ self,
+ device_id: str,
+ *,
+ action: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Perform a global action
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ f"/devices/{device_id}/global",
+ body=await async_maybe_transform({"action": action}, action_global_params.ActionGlobalParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def swipe(
+ self,
+ device_id: str,
+ *,
+ duration: int,
+ end_x: int,
+ end_y: int,
+ start_x: int,
+ start_y: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Swipe
+
+ Args:
+ duration: Swipe duration in milliseconds
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ f"/devices/{device_id}/swipe",
+ body=await async_maybe_transform(
+ {
+ "duration": duration,
+ "end_x": end_x,
+ "end_y": end_y,
+ "start_x": start_x,
+ "start_y": start_y,
+ },
+ action_swipe_params.ActionSwipeParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def tap(
+ self,
+ device_id: str,
+ *,
+ x: int,
+ y: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Tap by coordinates
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ f"/devices/{device_id}/tap",
+ body=await async_maybe_transform(
+ {
+ "x": x,
+ "y": y,
+ },
+ action_tap_params.ActionTapParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class ActionsResourceWithRawResponse:
+ def __init__(self, actions: ActionsResource) -> None:
+ self._actions = actions
+
+ self.global_ = to_raw_response_wrapper(
+ actions.global_,
+ )
+ self.swipe = to_raw_response_wrapper(
+ actions.swipe,
+ )
+ self.tap = to_raw_response_wrapper(
+ actions.tap,
+ )
+
+
+class AsyncActionsResourceWithRawResponse:
+ def __init__(self, actions: AsyncActionsResource) -> None:
+ self._actions = actions
+
+ self.global_ = async_to_raw_response_wrapper(
+ actions.global_,
+ )
+ self.swipe = async_to_raw_response_wrapper(
+ actions.swipe,
+ )
+ self.tap = async_to_raw_response_wrapper(
+ actions.tap,
+ )
+
+
+class ActionsResourceWithStreamingResponse:
+ def __init__(self, actions: ActionsResource) -> None:
+ self._actions = actions
+
+ self.global_ = to_streamed_response_wrapper(
+ actions.global_,
+ )
+ self.swipe = to_streamed_response_wrapper(
+ actions.swipe,
+ )
+ self.tap = to_streamed_response_wrapper(
+ actions.tap,
+ )
+
+
+class AsyncActionsResourceWithStreamingResponse:
+ def __init__(self, actions: AsyncActionsResource) -> None:
+ self._actions = actions
+
+ self.global_ = async_to_streamed_response_wrapper(
+ actions.global_,
+ )
+ self.swipe = async_to_streamed_response_wrapper(
+ actions.swipe,
+ )
+ self.tap = async_to_streamed_response_wrapper(
+ actions.tap,
+ )
diff --git a/src/mobilerun/resources/devices/apps.py b/src/mobilerun/resources/devices/apps.py
new file mode 100644
index 0000000..e0ddd9b
--- /dev/null
+++ b/src/mobilerun/resources/devices/apps.py
@@ -0,0 +1,495 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
+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.devices import app_list_params, app_start_params, app_install_params
+from ...types.devices.app_list_response import AppListResponse
+
+__all__ = ["AppsResource", "AsyncAppsResource"]
+
+
+class AppsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AppsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AppsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AppsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AppsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ device_id: str,
+ *,
+ include_system_apps: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> Optional[AppListResponse]:
+ """
+ List apps
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ f"/devices/{device_id}/apps",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"include_system_apps": include_system_apps}, app_list_params.AppListParams),
+ ),
+ cast_to=AppListResponse,
+ )
+
+ def delete(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Delete app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._delete(
+ f"/devices/{device_id}/apps/{package_name}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def install(
+ self,
+ device_id: str,
+ *,
+ package_name: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Install app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ f"/devices/{device_id}/apps",
+ body=maybe_transform({"package_name": package_name}, app_install_params.AppInstallParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def start(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ activity: str | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Start app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._put(
+ f"/devices/{device_id}/apps/{package_name}",
+ body=maybe_transform({"activity": activity}, app_start_params.AppStartParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncAppsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAppsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAppsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAppsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncAppsResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ device_id: str,
+ *,
+ include_system_apps: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> Optional[AppListResponse]:
+ """
+ List apps
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ f"/devices/{device_id}/apps",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"include_system_apps": include_system_apps}, app_list_params.AppListParams
+ ),
+ ),
+ cast_to=AppListResponse,
+ )
+
+ async def delete(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Delete app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._delete(
+ f"/devices/{device_id}/apps/{package_name}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def install(
+ self,
+ device_id: str,
+ *,
+ package_name: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Install app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ f"/devices/{device_id}/apps",
+ body=await async_maybe_transform({"package_name": package_name}, app_install_params.AppInstallParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def start(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ activity: str | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Start app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._put(
+ f"/devices/{device_id}/apps/{package_name}",
+ body=await async_maybe_transform({"activity": activity}, app_start_params.AppStartParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AppsResourceWithRawResponse:
+ def __init__(self, apps: AppsResource) -> None:
+ self._apps = apps
+
+ self.list = to_raw_response_wrapper(
+ apps.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ apps.delete,
+ )
+ self.install = to_raw_response_wrapper(
+ apps.install,
+ )
+ self.start = to_raw_response_wrapper(
+ apps.start,
+ )
+
+
+class AsyncAppsResourceWithRawResponse:
+ def __init__(self, apps: AsyncAppsResource) -> None:
+ self._apps = apps
+
+ self.list = async_to_raw_response_wrapper(
+ apps.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ apps.delete,
+ )
+ self.install = async_to_raw_response_wrapper(
+ apps.install,
+ )
+ self.start = async_to_raw_response_wrapper(
+ apps.start,
+ )
+
+
+class AppsResourceWithStreamingResponse:
+ def __init__(self, apps: AppsResource) -> None:
+ self._apps = apps
+
+ self.list = to_streamed_response_wrapper(
+ apps.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ apps.delete,
+ )
+ self.install = to_streamed_response_wrapper(
+ apps.install,
+ )
+ self.start = to_streamed_response_wrapper(
+ apps.start,
+ )
+
+
+class AsyncAppsResourceWithStreamingResponse:
+ def __init__(self, apps: AsyncAppsResource) -> None:
+ self._apps = apps
+
+ self.list = async_to_streamed_response_wrapper(
+ apps.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ apps.delete,
+ )
+ self.install = async_to_streamed_response_wrapper(
+ apps.install,
+ )
+ self.start = async_to_streamed_response_wrapper(
+ apps.start,
+ )
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
new file mode 100644
index 0000000..63be619
--- /dev/null
+++ b/src/mobilerun/resources/devices/devices.py
@@ -0,0 +1,820 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal
+
+import httpx
+
+from .apps import (
+ AppsResource,
+ AsyncAppsResource,
+ AppsResourceWithRawResponse,
+ AsyncAppsResourceWithRawResponse,
+ AppsResourceWithStreamingResponse,
+ AsyncAppsResourceWithStreamingResponse,
+)
+from .state import (
+ StateResource,
+ AsyncStateResource,
+ StateResourceWithRawResponse,
+ AsyncStateResourceWithRawResponse,
+ StateResourceWithStreamingResponse,
+ AsyncStateResourceWithStreamingResponse,
+)
+from .tasks import (
+ TasksResource,
+ AsyncTasksResource,
+ TasksResourceWithRawResponse,
+ AsyncTasksResourceWithRawResponse,
+ TasksResourceWithStreamingResponse,
+ AsyncTasksResourceWithStreamingResponse,
+)
+from ...types import device_list_params, device_create_params
+from .actions import (
+ ActionsResource,
+ AsyncActionsResource,
+ ActionsResourceWithRawResponse,
+ AsyncActionsResourceWithRawResponse,
+ ActionsResourceWithStreamingResponse,
+ AsyncActionsResourceWithStreamingResponse,
+)
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from .keyboard import (
+ KeyboardResource,
+ AsyncKeyboardResource,
+ KeyboardResourceWithRawResponse,
+ AsyncKeyboardResourceWithRawResponse,
+ KeyboardResourceWithStreamingResponse,
+ AsyncKeyboardResourceWithStreamingResponse,
+)
+from .packages import (
+ PackagesResource,
+ AsyncPackagesResource,
+ PackagesResourceWithRawResponse,
+ AsyncPackagesResourceWithRawResponse,
+ PackagesResourceWithStreamingResponse,
+ AsyncPackagesResourceWithStreamingResponse,
+)
+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.device import Device
+from ...types.device_list_response import DeviceListResponse
+from ...types.device_count_response import DeviceCountResponse
+
+__all__ = ["DevicesResource", "AsyncDevicesResource"]
+
+
+class DevicesResource(SyncAPIResource):
+ @cached_property
+ def actions(self) -> ActionsResource:
+ return ActionsResource(self._client)
+
+ @cached_property
+ def state(self) -> StateResource:
+ return StateResource(self._client)
+
+ @cached_property
+ def apps(self) -> AppsResource:
+ return AppsResource(self._client)
+
+ @cached_property
+ def packages(self) -> PackagesResource:
+ return PackagesResource(self._client)
+
+ @cached_property
+ def keyboard(self) -> KeyboardResource:
+ return KeyboardResource(self._client)
+
+ @cached_property
+ def tasks(self) -> TasksResource:
+ return TasksResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> DevicesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return DevicesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> DevicesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return DevicesResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
+ provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
+ apps: Optional[SequenceNotStr[str]] | Omit = omit,
+ country: str | Omit = omit,
+ files: Optional[SequenceNotStr[str]] | Omit = omit,
+ name: str | Omit = omit,
+ proxy: device_create_params.Proxy | Omit = omit,
+ # 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,
+ ) -> Device:
+ """
+ Provision a new device
+
+ 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
+ """
+ return self._post(
+ "/devices",
+ body=maybe_transform(
+ {
+ "apps": apps,
+ "country": country,
+ "files": files,
+ "name": name,
+ "proxy": proxy,
+ },
+ device_create_params.DeviceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "device_type": device_type,
+ "provider": provider,
+ },
+ device_create_params.DeviceCreateParams,
+ ),
+ ),
+ cast_to=Device,
+ )
+
+ def retrieve(
+ self,
+ device_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,
+ ) -> Device:
+ """
+ Get device info
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return self._get(
+ f"/devices/{device_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Device,
+ )
+
+ def list(
+ self,
+ *,
+ country: str | Omit = omit,
+ name: str | Omit = omit,
+ order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
+ state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
+ type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
+ # 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,
+ ) -> DeviceListResponse:
+ """
+ List devices
+
+ 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
+ """
+ return self._get(
+ "/devices",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "country": country,
+ "name": name,
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ "provider": provider,
+ "state": state,
+ "type": type,
+ },
+ device_list_params.DeviceListParams,
+ ),
+ ),
+ cast_to=DeviceListResponse,
+ )
+
+ def count(
+ self,
+ *,
+ # 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,
+ ) -> DeviceCountResponse:
+ """Count claimed devices"""
+ return self._get(
+ "/devices/count",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DeviceCountResponse,
+ )
+
+ def terminate(
+ self,
+ device_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,
+ ) -> None:
+ """
+ Terminate a device
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._delete(
+ f"/devices/{device_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def wait_ready(
+ self,
+ device_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,
+ ) -> Device:
+ """
+ Wait for device to be ready
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return self._get(
+ f"/devices/{device_id}/wait",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Device,
+ )
+
+
+class AsyncDevicesResource(AsyncAPIResource):
+ @cached_property
+ def actions(self) -> AsyncActionsResource:
+ return AsyncActionsResource(self._client)
+
+ @cached_property
+ def state(self) -> AsyncStateResource:
+ return AsyncStateResource(self._client)
+
+ @cached_property
+ def apps(self) -> AsyncAppsResource:
+ return AsyncAppsResource(self._client)
+
+ @cached_property
+ def packages(self) -> AsyncPackagesResource:
+ return AsyncPackagesResource(self._client)
+
+ @cached_property
+ def keyboard(self) -> AsyncKeyboardResource:
+ return AsyncKeyboardResource(self._client)
+
+ @cached_property
+ def tasks(self) -> AsyncTasksResource:
+ return AsyncTasksResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncDevicesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncDevicesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncDevicesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncDevicesResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
+ provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
+ apps: Optional[SequenceNotStr[str]] | Omit = omit,
+ country: str | Omit = omit,
+ files: Optional[SequenceNotStr[str]] | Omit = omit,
+ name: str | Omit = omit,
+ proxy: device_create_params.Proxy | Omit = omit,
+ # 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,
+ ) -> Device:
+ """
+ Provision a new device
+
+ 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
+ """
+ return await self._post(
+ "/devices",
+ body=await async_maybe_transform(
+ {
+ "apps": apps,
+ "country": country,
+ "files": files,
+ "name": name,
+ "proxy": proxy,
+ },
+ device_create_params.DeviceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "device_type": device_type,
+ "provider": provider,
+ },
+ device_create_params.DeviceCreateParams,
+ ),
+ ),
+ cast_to=Device,
+ )
+
+ async def retrieve(
+ self,
+ device_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,
+ ) -> Device:
+ """
+ Get device info
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return await self._get(
+ f"/devices/{device_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Device,
+ )
+
+ async def list(
+ self,
+ *,
+ country: str | Omit = omit,
+ name: str | Omit = omit,
+ order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
+ state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
+ type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
+ # 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,
+ ) -> DeviceListResponse:
+ """
+ List devices
+
+ 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
+ """
+ return await self._get(
+ "/devices",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "country": country,
+ "name": name,
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ "provider": provider,
+ "state": state,
+ "type": type,
+ },
+ device_list_params.DeviceListParams,
+ ),
+ ),
+ cast_to=DeviceListResponse,
+ )
+
+ async def count(
+ self,
+ *,
+ # 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,
+ ) -> DeviceCountResponse:
+ """Count claimed devices"""
+ return await self._get(
+ "/devices/count",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=DeviceCountResponse,
+ )
+
+ async def terminate(
+ self,
+ device_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,
+ ) -> None:
+ """
+ Terminate a device
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._delete(
+ f"/devices/{device_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def wait_ready(
+ self,
+ device_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,
+ ) -> Device:
+ """
+ Wait for device to be ready
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return await self._get(
+ f"/devices/{device_id}/wait",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Device,
+ )
+
+
+class DevicesResourceWithRawResponse:
+ def __init__(self, devices: DevicesResource) -> None:
+ self._devices = devices
+
+ self.create = to_raw_response_wrapper(
+ devices.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ devices.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ devices.list,
+ )
+ self.count = to_raw_response_wrapper(
+ devices.count,
+ )
+ self.terminate = to_raw_response_wrapper(
+ devices.terminate,
+ )
+ self.wait_ready = to_raw_response_wrapper(
+ devices.wait_ready,
+ )
+
+ @cached_property
+ def actions(self) -> ActionsResourceWithRawResponse:
+ return ActionsResourceWithRawResponse(self._devices.actions)
+
+ @cached_property
+ def state(self) -> StateResourceWithRawResponse:
+ return StateResourceWithRawResponse(self._devices.state)
+
+ @cached_property
+ def apps(self) -> AppsResourceWithRawResponse:
+ return AppsResourceWithRawResponse(self._devices.apps)
+
+ @cached_property
+ def packages(self) -> PackagesResourceWithRawResponse:
+ return PackagesResourceWithRawResponse(self._devices.packages)
+
+ @cached_property
+ def keyboard(self) -> KeyboardResourceWithRawResponse:
+ return KeyboardResourceWithRawResponse(self._devices.keyboard)
+
+ @cached_property
+ def tasks(self) -> TasksResourceWithRawResponse:
+ return TasksResourceWithRawResponse(self._devices.tasks)
+
+
+class AsyncDevicesResourceWithRawResponse:
+ def __init__(self, devices: AsyncDevicesResource) -> None:
+ self._devices = devices
+
+ self.create = async_to_raw_response_wrapper(
+ devices.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ devices.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ devices.list,
+ )
+ self.count = async_to_raw_response_wrapper(
+ devices.count,
+ )
+ self.terminate = async_to_raw_response_wrapper(
+ devices.terminate,
+ )
+ self.wait_ready = async_to_raw_response_wrapper(
+ devices.wait_ready,
+ )
+
+ @cached_property
+ def actions(self) -> AsyncActionsResourceWithRawResponse:
+ return AsyncActionsResourceWithRawResponse(self._devices.actions)
+
+ @cached_property
+ def state(self) -> AsyncStateResourceWithRawResponse:
+ return AsyncStateResourceWithRawResponse(self._devices.state)
+
+ @cached_property
+ def apps(self) -> AsyncAppsResourceWithRawResponse:
+ return AsyncAppsResourceWithRawResponse(self._devices.apps)
+
+ @cached_property
+ def packages(self) -> AsyncPackagesResourceWithRawResponse:
+ return AsyncPackagesResourceWithRawResponse(self._devices.packages)
+
+ @cached_property
+ def keyboard(self) -> AsyncKeyboardResourceWithRawResponse:
+ return AsyncKeyboardResourceWithRawResponse(self._devices.keyboard)
+
+ @cached_property
+ def tasks(self) -> AsyncTasksResourceWithRawResponse:
+ return AsyncTasksResourceWithRawResponse(self._devices.tasks)
+
+
+class DevicesResourceWithStreamingResponse:
+ def __init__(self, devices: DevicesResource) -> None:
+ self._devices = devices
+
+ self.create = to_streamed_response_wrapper(
+ devices.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ devices.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ devices.list,
+ )
+ self.count = to_streamed_response_wrapper(
+ devices.count,
+ )
+ self.terminate = to_streamed_response_wrapper(
+ devices.terminate,
+ )
+ self.wait_ready = to_streamed_response_wrapper(
+ devices.wait_ready,
+ )
+
+ @cached_property
+ def actions(self) -> ActionsResourceWithStreamingResponse:
+ return ActionsResourceWithStreamingResponse(self._devices.actions)
+
+ @cached_property
+ def state(self) -> StateResourceWithStreamingResponse:
+ return StateResourceWithStreamingResponse(self._devices.state)
+
+ @cached_property
+ def apps(self) -> AppsResourceWithStreamingResponse:
+ return AppsResourceWithStreamingResponse(self._devices.apps)
+
+ @cached_property
+ def packages(self) -> PackagesResourceWithStreamingResponse:
+ return PackagesResourceWithStreamingResponse(self._devices.packages)
+
+ @cached_property
+ def keyboard(self) -> KeyboardResourceWithStreamingResponse:
+ return KeyboardResourceWithStreamingResponse(self._devices.keyboard)
+
+ @cached_property
+ def tasks(self) -> TasksResourceWithStreamingResponse:
+ return TasksResourceWithStreamingResponse(self._devices.tasks)
+
+
+class AsyncDevicesResourceWithStreamingResponse:
+ def __init__(self, devices: AsyncDevicesResource) -> None:
+ self._devices = devices
+
+ self.create = async_to_streamed_response_wrapper(
+ devices.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ devices.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ devices.list,
+ )
+ self.count = async_to_streamed_response_wrapper(
+ devices.count,
+ )
+ self.terminate = async_to_streamed_response_wrapper(
+ devices.terminate,
+ )
+ self.wait_ready = async_to_streamed_response_wrapper(
+ devices.wait_ready,
+ )
+
+ @cached_property
+ def actions(self) -> AsyncActionsResourceWithStreamingResponse:
+ return AsyncActionsResourceWithStreamingResponse(self._devices.actions)
+
+ @cached_property
+ def state(self) -> AsyncStateResourceWithStreamingResponse:
+ return AsyncStateResourceWithStreamingResponse(self._devices.state)
+
+ @cached_property
+ def apps(self) -> AsyncAppsResourceWithStreamingResponse:
+ return AsyncAppsResourceWithStreamingResponse(self._devices.apps)
+
+ @cached_property
+ def packages(self) -> AsyncPackagesResourceWithStreamingResponse:
+ return AsyncPackagesResourceWithStreamingResponse(self._devices.packages)
+
+ @cached_property
+ def keyboard(self) -> AsyncKeyboardResourceWithStreamingResponse:
+ return AsyncKeyboardResourceWithStreamingResponse(self._devices.keyboard)
+
+ @cached_property
+ def tasks(self) -> AsyncTasksResourceWithStreamingResponse:
+ return AsyncTasksResourceWithStreamingResponse(self._devices.tasks)
diff --git a/src/mobilerun/resources/devices/keyboard.py b/src/mobilerun/resources/devices/keyboard.py
new file mode 100644
index 0000000..81d8459
--- /dev/null
+++ b/src/mobilerun/resources/devices/keyboard.py
@@ -0,0 +1,390 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
+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.devices import keyboard_key_params, keyboard_write_params
+
+__all__ = ["KeyboardResource", "AsyncKeyboardResource"]
+
+
+class KeyboardResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> KeyboardResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return KeyboardResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> KeyboardResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return KeyboardResourceWithStreamingResponse(self)
+
+ def clear(
+ self,
+ device_id: str,
+ *,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Clear input
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._delete(
+ f"/devices/{device_id}/keyboard",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def key(
+ self,
+ device_id: str,
+ *,
+ key: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Input key
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._put(
+ f"/devices/{device_id}/keyboard",
+ body=maybe_transform({"key": key}, keyboard_key_params.KeyboardKeyParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def write(
+ self,
+ device_id: str,
+ *,
+ clear: bool,
+ text: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Input text
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ f"/devices/{device_id}/keyboard",
+ body=maybe_transform(
+ {
+ "clear": clear,
+ "text": text,
+ },
+ keyboard_write_params.KeyboardWriteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncKeyboardResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncKeyboardResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncKeyboardResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncKeyboardResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncKeyboardResourceWithStreamingResponse(self)
+
+ async def clear(
+ self,
+ device_id: str,
+ *,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Clear input
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._delete(
+ f"/devices/{device_id}/keyboard",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def key(
+ self,
+ device_id: str,
+ *,
+ key: int,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Input key
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._put(
+ f"/devices/{device_id}/keyboard",
+ body=await async_maybe_transform({"key": key}, keyboard_key_params.KeyboardKeyParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def write(
+ self,
+ device_id: str,
+ *,
+ clear: bool,
+ text: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Input text
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ f"/devices/{device_id}/keyboard",
+ body=await async_maybe_transform(
+ {
+ "clear": clear,
+ "text": text,
+ },
+ keyboard_write_params.KeyboardWriteParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class KeyboardResourceWithRawResponse:
+ def __init__(self, keyboard: KeyboardResource) -> None:
+ self._keyboard = keyboard
+
+ self.clear = to_raw_response_wrapper(
+ keyboard.clear,
+ )
+ self.key = to_raw_response_wrapper(
+ keyboard.key,
+ )
+ self.write = to_raw_response_wrapper(
+ keyboard.write,
+ )
+
+
+class AsyncKeyboardResourceWithRawResponse:
+ def __init__(self, keyboard: AsyncKeyboardResource) -> None:
+ self._keyboard = keyboard
+
+ self.clear = async_to_raw_response_wrapper(
+ keyboard.clear,
+ )
+ self.key = async_to_raw_response_wrapper(
+ keyboard.key,
+ )
+ self.write = async_to_raw_response_wrapper(
+ keyboard.write,
+ )
+
+
+class KeyboardResourceWithStreamingResponse:
+ def __init__(self, keyboard: KeyboardResource) -> None:
+ self._keyboard = keyboard
+
+ self.clear = to_streamed_response_wrapper(
+ keyboard.clear,
+ )
+ self.key = to_streamed_response_wrapper(
+ keyboard.key,
+ )
+ self.write = to_streamed_response_wrapper(
+ keyboard.write,
+ )
+
+
+class AsyncKeyboardResourceWithStreamingResponse:
+ def __init__(self, keyboard: AsyncKeyboardResource) -> None:
+ self._keyboard = keyboard
+
+ self.clear = async_to_streamed_response_wrapper(
+ keyboard.clear,
+ )
+ self.key = async_to_streamed_response_wrapper(
+ keyboard.key,
+ )
+ self.write = async_to_streamed_response_wrapper(
+ keyboard.write,
+ )
diff --git a/src/mobilerun/resources/devices/packages.py b/src/mobilerun/resources/devices/packages.py
new file mode 100644
index 0000000..ed3ead4
--- /dev/null
+++ b/src/mobilerun/resources/devices/packages.py
@@ -0,0 +1,195 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
+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.devices import package_list_params
+from ...types.devices.package_list_response import PackageListResponse
+
+__all__ = ["PackagesResource", "AsyncPackagesResource"]
+
+
+class PackagesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> PackagesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return PackagesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> PackagesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return PackagesResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ device_id: str,
+ *,
+ include_system_packages: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> Optional[PackageListResponse]:
+ """
+ List packages
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ f"/devices/{device_id}/packages",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {"include_system_packages": include_system_packages}, package_list_params.PackageListParams
+ ),
+ ),
+ cast_to=PackageListResponse,
+ )
+
+
+class AsyncPackagesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncPackagesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncPackagesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncPackagesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncPackagesResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ device_id: str,
+ *,
+ include_system_packages: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> Optional[PackageListResponse]:
+ """
+ List packages
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ f"/devices/{device_id}/packages",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"include_system_packages": include_system_packages}, package_list_params.PackageListParams
+ ),
+ ),
+ cast_to=PackageListResponse,
+ )
+
+
+class PackagesResourceWithRawResponse:
+ def __init__(self, packages: PackagesResource) -> None:
+ self._packages = packages
+
+ self.list = to_raw_response_wrapper(
+ packages.list,
+ )
+
+
+class AsyncPackagesResourceWithRawResponse:
+ def __init__(self, packages: AsyncPackagesResource) -> None:
+ self._packages = packages
+
+ self.list = async_to_raw_response_wrapper(
+ packages.list,
+ )
+
+
+class PackagesResourceWithStreamingResponse:
+ def __init__(self, packages: PackagesResource) -> None:
+ self._packages = packages
+
+ self.list = to_streamed_response_wrapper(
+ packages.list,
+ )
+
+
+class AsyncPackagesResourceWithStreamingResponse:
+ def __init__(self, packages: AsyncPackagesResource) -> None:
+ self._packages = packages
+
+ self.list = async_to_streamed_response_wrapper(
+ packages.list,
+ )
diff --git a/src/mobilerun/resources/devices/state.py b/src/mobilerun/resources/devices/state.py
new file mode 100644
index 0000000..10521ea
--- /dev/null
+++ b/src/mobilerun/resources/devices/state.py
@@ -0,0 +1,385 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import is_given, maybe_transform, strip_not_given, async_maybe_transform
+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.devices import state_ui_params, state_screenshot_params
+from ...types.devices.state_ui_response import StateUiResponse
+
+__all__ = ["StateResource", "AsyncStateResource"]
+
+
+class StateResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> StateResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return StateResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> StateResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return StateResourceWithStreamingResponse(self)
+
+ def screenshot(
+ self,
+ device_id: str,
+ *,
+ hide_overlay: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> str:
+ """
+ Take screenshot
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ f"/devices/{device_id}/screenshot",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"hide_overlay": hide_overlay}, state_screenshot_params.StateScreenshotParams),
+ ),
+ cast_to=str,
+ )
+
+ def time(
+ self,
+ device_id: str,
+ *,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> str:
+ """
+ Device time
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ f"/devices/{device_id}/time",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=str,
+ )
+
+ def ui(
+ self,
+ device_id: str,
+ *,
+ filter: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> StateUiResponse:
+ """
+ UI state
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ f"/devices/{device_id}/ui-state",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"filter": filter}, state_ui_params.StateUiParams),
+ ),
+ cast_to=StateUiResponse,
+ )
+
+
+class AsyncStateResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncStateResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncStateResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncStateResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncStateResourceWithStreamingResponse(self)
+
+ async def screenshot(
+ self,
+ device_id: str,
+ *,
+ hide_overlay: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> str:
+ """
+ Take screenshot
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ f"/devices/{device_id}/screenshot",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"hide_overlay": hide_overlay}, state_screenshot_params.StateScreenshotParams
+ ),
+ ),
+ cast_to=str,
+ )
+
+ async def time(
+ self,
+ device_id: str,
+ *,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> str:
+ """
+ Device time
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ f"/devices/{device_id}/time",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=str,
+ )
+
+ async def ui(
+ self,
+ device_id: str,
+ *,
+ filter: bool | Omit = omit,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> StateUiResponse:
+ """
+ UI state
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ f"/devices/{device_id}/ui-state",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"filter": filter}, state_ui_params.StateUiParams),
+ ),
+ cast_to=StateUiResponse,
+ )
+
+
+class StateResourceWithRawResponse:
+ def __init__(self, state: StateResource) -> None:
+ self._state = state
+
+ self.screenshot = to_raw_response_wrapper(
+ state.screenshot,
+ )
+ self.time = to_raw_response_wrapper(
+ state.time,
+ )
+ self.ui = to_raw_response_wrapper(
+ state.ui,
+ )
+
+
+class AsyncStateResourceWithRawResponse:
+ def __init__(self, state: AsyncStateResource) -> None:
+ self._state = state
+
+ self.screenshot = async_to_raw_response_wrapper(
+ state.screenshot,
+ )
+ self.time = async_to_raw_response_wrapper(
+ state.time,
+ )
+ self.ui = async_to_raw_response_wrapper(
+ state.ui,
+ )
+
+
+class StateResourceWithStreamingResponse:
+ def __init__(self, state: StateResource) -> None:
+ self._state = state
+
+ self.screenshot = to_streamed_response_wrapper(
+ state.screenshot,
+ )
+ self.time = to_streamed_response_wrapper(
+ state.time,
+ )
+ self.ui = to_streamed_response_wrapper(
+ state.ui,
+ )
+
+
+class AsyncStateResourceWithStreamingResponse:
+ def __init__(self, state: AsyncStateResource) -> None:
+ self._state = state
+
+ self.screenshot = async_to_streamed_response_wrapper(
+ state.screenshot,
+ )
+ self.time = async_to_streamed_response_wrapper(
+ state.time,
+ )
+ self.ui = async_to_streamed_response_wrapper(
+ state.ui,
+ )
diff --git a/src/mobilerun/resources/devices/tasks.py b/src/mobilerun/resources/devices/tasks.py
new file mode 100644
index 0000000..69e27f4
--- /dev/null
+++ b/src/mobilerun/resources/devices/tasks.py
@@ -0,0 +1,199 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+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.devices import task_list_params
+from ...types.devices.task_list_response import TaskListResponse
+
+__all__ = ["TasksResource", "AsyncTasksResource"]
+
+
+class TasksResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> TasksResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return TasksResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> TasksResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return TasksResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ device_id: str,
+ *,
+ order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ # 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,
+ ) -> TaskListResponse:
+ """
+ List tasks for a device
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return self._get(
+ f"/devices/{device_id}/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ },
+ task_list_params.TaskListParams,
+ ),
+ ),
+ cast_to=TaskListResponse,
+ )
+
+
+class AsyncTasksResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncTasksResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncTasksResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncTasksResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response
+ """
+ return AsyncTasksResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ device_id: str,
+ *,
+ order_by: Literal["id", "createdAt", "updatedAt", "assignedAt"] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ # 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,
+ ) -> TaskListResponse:
+ """
+ List tasks for a device
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ return await self._get(
+ f"/devices/{device_id}/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ },
+ task_list_params.TaskListParams,
+ ),
+ ),
+ cast_to=TaskListResponse,
+ )
+
+
+class TasksResourceWithRawResponse:
+ def __init__(self, tasks: TasksResource) -> None:
+ self._tasks = tasks
+
+ self.list = to_raw_response_wrapper(
+ tasks.list,
+ )
+
+
+class AsyncTasksResourceWithRawResponse:
+ def __init__(self, tasks: AsyncTasksResource) -> None:
+ self._tasks = tasks
+
+ self.list = async_to_raw_response_wrapper(
+ tasks.list,
+ )
+
+
+class TasksResourceWithStreamingResponse:
+ def __init__(self, tasks: TasksResource) -> None:
+ self._tasks = tasks
+
+ self.list = to_streamed_response_wrapper(
+ tasks.list,
+ )
+
+
+class AsyncTasksResourceWithStreamingResponse:
+ def __init__(self, tasks: AsyncTasksResource) -> None:
+ self._tasks = tasks
+
+ self.list = async_to_streamed_response_wrapper(
+ tasks.list,
+ )
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index 48e9ccc..72eddf4 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -3,6 +3,7 @@
from __future__ import annotations
from .task import Task as Task
+from .device import Device as Device
from .llm_model import LlmModel as LlmModel
from .task_status import TaskStatus as TaskStatus
from .app_list_params import AppListParams as AppListParams
@@ -11,11 +12,15 @@
from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
from .task_run_response import TaskRunResponse as TaskRunResponse
+from .device_list_params import DeviceListParams as DeviceListParams
from .hook_list_response import HookListResponse as HookListResponse
from .hook_update_params import HookUpdateParams as HookUpdateParams
from .task_list_response import TaskListResponse as TaskListResponse
from .task_stop_response import TaskStopResponse as TaskStopResponse
+from .device_create_params import DeviceCreateParams as DeviceCreateParams
+from .device_list_response import DeviceListResponse as DeviceListResponse
from .hook_update_response import HookUpdateResponse as HookUpdateResponse
+from .device_count_response import DeviceCountResponse as DeviceCountResponse
from .hook_perform_response import HookPerformResponse as HookPerformResponse
from .hook_subscribe_params import HookSubscribeParams as HookSubscribeParams
from .hook_retrieve_response import HookRetrieveResponse as HookRetrieveResponse
diff --git a/src/mobilerun/types/device.py b/src/mobilerun/types/device.py
new file mode 100644
index 0000000..3d570c1
--- /dev/null
+++ b/src/mobilerun/types/device.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["Device"]
+
+
+class Device(BaseModel):
+ id: str
+
+ apps: Optional[List[str]] = None
+
+ assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None)
+
+ country: str
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ device_type: str = FieldInfo(alias="deviceType")
+
+ files: Optional[List[str]] = None
+
+ name: str
+
+ provider: str
+
+ state: str
+
+ state_message: str = FieldInfo(alias="stateMessage")
+
+ stream_token: str = FieldInfo(alias="streamToken")
+
+ stream_url: str = FieldInfo(alias="streamUrl")
+
+ task_count: int = FieldInfo(alias="taskCount")
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ user_id: Optional[str] = FieldInfo(alias="userId", default=None)
diff --git a/src/mobilerun/types/device_count_response.py b/src/mobilerun/types/device_count_response.py
new file mode 100644
index 0000000..517cdeb
--- /dev/null
+++ b/src/mobilerun/types/device_count_response.py
@@ -0,0 +1,22 @@
+# 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__ = ["DeviceCountResponse"]
+
+
+class DeviceCountResponse(BaseModel):
+ limrun: int
+
+ personal: int
+
+ remote: int
+
+ roidrun: int
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/device_create_params.py b/src/mobilerun/types/device_create_params.py
new file mode 100644
index 0000000..4134f5a
--- /dev/null
+++ b/src/mobilerun/types/device_create_params.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._types import SequenceNotStr
+from .._utils import PropertyInfo
+
+__all__ = ["DeviceCreateParams", "Proxy"]
+
+
+class DeviceCreateParams(TypedDict, total=False):
+ device_type: Annotated[
+ Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"],
+ PropertyInfo(alias="deviceType"),
+ ]
+
+ provider: Literal["limrun", "remote", "roidrun"]
+
+ apps: Optional[SequenceNotStr[str]]
+
+ country: str
+
+ files: Optional[SequenceNotStr[str]]
+
+ name: str
+
+ proxy: Proxy
+
+
+class Proxy(TypedDict, total=False):
+ host: Required[str]
+
+ password: Required[str]
+
+ port: Required[int]
+
+ user: Required[str]
diff --git a/src/mobilerun/types/device_list_params.py b/src/mobilerun/types/device_list_params.py
new file mode 100644
index 0000000..48b5c7f
--- /dev/null
+++ b/src/mobilerun/types/device_list_params.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["DeviceListParams"]
+
+
+class DeviceListParams(TypedDict, total=False):
+ country: str
+
+ name: str
+
+ order_by: Annotated[Literal["id", "createdAt", "updatedAt", "assignedAt"], PropertyInfo(alias="orderBy")]
+
+ order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
+
+ page: int
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+
+ provider: Literal["limrun", "personal", "remote", "roidrun"]
+
+ state: Literal["creating", "assigned", "ready", "terminated", "unknown"]
+
+ type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"]
diff --git a/src/mobilerun/types/device_list_response.py b/src/mobilerun/types/device_list_response.py
new file mode 100644
index 0000000..cd6cc01
--- /dev/null
+++ b/src/mobilerun/types/device_list_response.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .device import Device
+from .._models import BaseModel
+
+__all__ = ["DeviceListResponse", "Pagination"]
+
+
+class Pagination(BaseModel):
+ has_next: bool = FieldInfo(alias="hasNext")
+
+ has_prev: bool = FieldInfo(alias="hasPrev")
+
+ page: int
+
+ pages: int
+
+ page_size: int = FieldInfo(alias="pageSize")
+
+ total: int
+
+
+class DeviceListResponse(BaseModel):
+ items: Optional[List[Device]] = None
+
+ pagination: Pagination
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/devices/__init__.py b/src/mobilerun/types/devices/__init__.py
index f8ee8b1..6bf3b6f 100644
--- a/src/mobilerun/types/devices/__init__.py
+++ b/src/mobilerun/types/devices/__init__.py
@@ -1,3 +1,22 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from __future__ import annotations
+
+from .app_list_params import AppListParams as AppListParams
+from .state_ui_params import StateUiParams as StateUiParams
+from .app_start_params import AppStartParams as AppStartParams
+from .task_list_params import TaskListParams as TaskListParams
+from .action_tap_params import ActionTapParams as ActionTapParams
+from .app_list_response import AppListResponse as AppListResponse
+from .state_ui_response import StateUiResponse as StateUiResponse
+from .app_install_params import AppInstallParams as AppInstallParams
+from .task_list_response import TaskListResponse as TaskListResponse
+from .action_swipe_params import ActionSwipeParams as ActionSwipeParams
+from .keyboard_key_params import KeyboardKeyParams as KeyboardKeyParams
+from .package_list_params import PackageListParams as PackageListParams
+from .state_time_response import StateTimeResponse as StateTimeResponse
+from .action_global_params import ActionGlobalParams as ActionGlobalParams
+from .keyboard_write_params import KeyboardWriteParams as KeyboardWriteParams
+from .package_list_response import PackageListResponse as PackageListResponse
+from .state_screenshot_params import StateScreenshotParams as StateScreenshotParams
+from .state_screenshot_response import StateScreenshotResponse as StateScreenshotResponse
diff --git a/src/mobilerun/types/devices/action_global_params.py b/src/mobilerun/types/devices/action_global_params.py
new file mode 100644
index 0000000..a8fca37
--- /dev/null
+++ b/src/mobilerun/types/devices/action_global_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ActionGlobalParams"]
+
+
+class ActionGlobalParams(TypedDict, total=False):
+ action: Required[int]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/action_swipe_params.py b/src/mobilerun/types/devices/action_swipe_params.py
new file mode 100644
index 0000000..2f9df10
--- /dev/null
+++ b/src/mobilerun/types/devices/action_swipe_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ActionSwipeParams"]
+
+
+class ActionSwipeParams(TypedDict, total=False):
+ duration: Required[int]
+ """Swipe duration in milliseconds"""
+
+ end_x: Required[Annotated[int, PropertyInfo(alias="endX")]]
+
+ end_y: Required[Annotated[int, PropertyInfo(alias="endY")]]
+
+ start_x: Required[Annotated[int, PropertyInfo(alias="startX")]]
+
+ start_y: Required[Annotated[int, PropertyInfo(alias="startY")]]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/action_tap_params.py b/src/mobilerun/types/devices/action_tap_params.py
new file mode 100644
index 0000000..006f57d
--- /dev/null
+++ b/src/mobilerun/types/devices/action_tap_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ActionTapParams"]
+
+
+class ActionTapParams(TypedDict, total=False):
+ x: Required[int]
+
+ y: Required[int]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_install_params.py b/src/mobilerun/types/devices/app_install_params.py
new file mode 100644
index 0000000..915231c
--- /dev/null
+++ b/src/mobilerun/types/devices/app_install_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["AppInstallParams"]
+
+
+class AppInstallParams(TypedDict, total=False):
+ package_name: Required[Annotated[str, PropertyInfo(alias="packageName")]]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_list_params.py b/src/mobilerun/types/devices/app_list_params.py
new file mode 100644
index 0000000..762be54
--- /dev/null
+++ b/src/mobilerun/types/devices/app_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["AppListParams"]
+
+
+class AppListParams(TypedDict, total=False):
+ include_system_apps: Annotated[bool, PropertyInfo(alias="includeSystemApps")]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/app_list_response.py b/src/mobilerun/types/devices/app_list_response.py
new file mode 100644
index 0000000..c8f8f4e
--- /dev/null
+++ b/src/mobilerun/types/devices/app_list_response.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+from typing_extensions import TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["AppListResponse", "AppListResponseItem"]
+
+
+class AppListResponseItem(BaseModel):
+ is_system_app: bool = FieldInfo(alias="isSystemApp")
+
+ label: str
+
+ package_name: str = FieldInfo(alias="packageName")
+
+ version_code: int = FieldInfo(alias="versionCode")
+
+ version_name: str = FieldInfo(alias="versionName")
+
+
+AppListResponse: TypeAlias = List[AppListResponseItem]
diff --git a/src/mobilerun/types/devices/app_start_params.py b/src/mobilerun/types/devices/app_start_params.py
new file mode 100644
index 0000000..f5761f1
--- /dev/null
+++ b/src/mobilerun/types/devices/app_start_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["AppStartParams"]
+
+
+class AppStartParams(TypedDict, total=False):
+ device_id: Required[Annotated[str, PropertyInfo(alias="deviceId")]]
+
+ activity: str
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/keyboard_key_params.py b/src/mobilerun/types/devices/keyboard_key_params.py
new file mode 100644
index 0000000..85854de
--- /dev/null
+++ b/src/mobilerun/types/devices/keyboard_key_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["KeyboardKeyParams"]
+
+
+class KeyboardKeyParams(TypedDict, total=False):
+ key: Required[int]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/keyboard_write_params.py b/src/mobilerun/types/devices/keyboard_write_params.py
new file mode 100644
index 0000000..69b8714
--- /dev/null
+++ b/src/mobilerun/types/devices/keyboard_write_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["KeyboardWriteParams"]
+
+
+class KeyboardWriteParams(TypedDict, total=False):
+ clear: Required[bool]
+
+ text: Required[str]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/package_list_params.py b/src/mobilerun/types/devices/package_list_params.py
new file mode 100644
index 0000000..450223e
--- /dev/null
+++ b/src/mobilerun/types/devices/package_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["PackageListParams"]
+
+
+class PackageListParams(TypedDict, total=False):
+ include_system_packages: Annotated[bool, PropertyInfo(alias="includeSystemPackages")]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/package_list_response.py b/src/mobilerun/types/devices/package_list_response.py
new file mode 100644
index 0000000..0ab9e4b
--- /dev/null
+++ b/src/mobilerun/types/devices/package_list_response.py
@@ -0,0 +1,8 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+from typing_extensions import TypeAlias
+
+__all__ = ["PackageListResponse"]
+
+PackageListResponse: TypeAlias = List[str]
diff --git a/src/mobilerun/types/devices/state_screenshot_params.py b/src/mobilerun/types/devices/state_screenshot_params.py
new file mode 100644
index 0000000..fa4d0bd
--- /dev/null
+++ b/src/mobilerun/types/devices/state_screenshot_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["StateScreenshotParams"]
+
+
+class StateScreenshotParams(TypedDict, total=False):
+ hide_overlay: Annotated[bool, PropertyInfo(alias="hideOverlay")]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/state_screenshot_response.py b/src/mobilerun/types/devices/state_screenshot_response.py
new file mode 100644
index 0000000..aaa4a93
--- /dev/null
+++ b/src/mobilerun/types/devices/state_screenshot_response.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import TypeAlias
+
+__all__ = ["StateScreenshotResponse"]
+
+StateScreenshotResponse: TypeAlias = str
diff --git a/src/mobilerun/types/devices/state_time_response.py b/src/mobilerun/types/devices/state_time_response.py
new file mode 100644
index 0000000..6aed1eb
--- /dev/null
+++ b/src/mobilerun/types/devices/state_time_response.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import TypeAlias
+
+__all__ = ["StateTimeResponse"]
+
+StateTimeResponse: TypeAlias = str
diff --git a/src/mobilerun/types/devices/state_ui_params.py b/src/mobilerun/types/devices/state_ui_params.py
new file mode 100644
index 0000000..de012d2
--- /dev/null
+++ b/src/mobilerun/types/devices/state_ui_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["StateUiParams"]
+
+
+class StateUiParams(TypedDict, total=False):
+ filter: bool
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun/types/devices/state_ui_response.py b/src/mobilerun/types/devices/state_ui_response.py
new file mode 100644
index 0000000..5254229
--- /dev/null
+++ b/src/mobilerun/types/devices/state_ui_response.py
@@ -0,0 +1,91 @@
+# 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__ = [
+ "StateUiResponse",
+ "DeviceContext",
+ "DeviceContextDisplayMetrics",
+ "DeviceContextFilteringParams",
+ "DeviceContextScreenBounds",
+ "DeviceContextScreenSize",
+ "PhoneState",
+ "PhoneStateFocusedElement",
+]
+
+
+class DeviceContextDisplayMetrics(BaseModel):
+ density: float
+
+ density_dpi: int = FieldInfo(alias="densityDpi")
+
+ height_pixels: int = FieldInfo(alias="heightPixels")
+
+ scaled_density: float = FieldInfo(alias="scaledDensity")
+
+ width_pixels: int = FieldInfo(alias="widthPixels")
+
+
+class DeviceContextFilteringParams(BaseModel):
+ min_element_size: int
+
+ overlay_offset: int
+
+
+class DeviceContextScreenBounds(BaseModel):
+ height: int
+
+ width: int
+
+
+class DeviceContextScreenSize(BaseModel):
+ height: int
+
+ width: int
+
+
+class DeviceContext(BaseModel):
+ display_metrics: DeviceContextDisplayMetrics
+
+ filtering_params: DeviceContextFilteringParams
+
+ screen_bounds: DeviceContextScreenBounds
+
+ screen_size: DeviceContextScreenSize = FieldInfo(alias="screenSize")
+
+
+class PhoneStateFocusedElement(BaseModel):
+ class_name: Optional[str] = FieldInfo(alias="className", default=None)
+
+ resource_id: Optional[str] = FieldInfo(alias="resourceId", default=None)
+
+ text: Optional[str] = None
+
+
+class PhoneState(BaseModel):
+ is_editable: bool = FieldInfo(alias="isEditable")
+
+ keyboard_visible: bool = FieldInfo(alias="keyboardVisible")
+
+ activity_name: Optional[str] = FieldInfo(alias="activityName", default=None)
+
+ current_app: Optional[str] = FieldInfo(alias="currentApp", default=None)
+
+ focused_element: Optional[PhoneStateFocusedElement] = FieldInfo(alias="focusedElement", default=None)
+
+ package_name: Optional[str] = FieldInfo(alias="packageName", default=None)
+
+
+class StateUiResponse(BaseModel):
+ a11y_tree: object
+
+ device_context: DeviceContext
+
+ phone_state: PhoneState
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun/types/devices/task_list_params.py b/src/mobilerun/types/devices/task_list_params.py
new file mode 100644
index 0000000..6c98a67
--- /dev/null
+++ b/src/mobilerun/types/devices/task_list_params.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["TaskListParams"]
+
+
+class TaskListParams(TypedDict, total=False):
+ order_by: Annotated[Literal["id", "createdAt", "updatedAt", "assignedAt"], PropertyInfo(alias="orderBy")]
+
+ order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
+
+ page: int
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun/types/devices/task_list_response.py b/src/mobilerun/types/devices/task_list_response.py
new file mode 100644
index 0000000..a767345
--- /dev/null
+++ b/src/mobilerun/types/devices/task_list_response.py
@@ -0,0 +1,41 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["TaskListResponse", "Item", "Pagination"]
+
+
+class Item(BaseModel):
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ task_id: str = FieldInfo(alias="taskId")
+
+ updated_at: datetime = FieldInfo(alias="updatedAt")
+
+
+class Pagination(BaseModel):
+ has_next: bool = FieldInfo(alias="hasNext")
+
+ has_prev: bool = FieldInfo(alias="hasPrev")
+
+ page: int
+
+ pages: int
+
+ page_size: int = FieldInfo(alias="pageSize")
+
+ total: int
+
+
+class TaskListResponse(BaseModel):
+ items: Optional[List[Item]] = None
+
+ pagination: Pagination
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/tests/api_resources/devices/__init__.py b/tests/api_resources/devices/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/devices/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/devices/test_actions.py b/tests/api_resources/devices/test_actions.py
new file mode 100644
index 0000000..dec3120
--- /dev/null
+++ b/tests/api_resources/devices/test_actions.py
@@ -0,0 +1,408 @@
+# 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 mobilerun import Mobilerun, AsyncMobilerun
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestActions:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_global(self, client: Mobilerun) -> None:
+ action = client.devices.actions.global_(
+ device_id="deviceId",
+ action=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_global_with_all_params(self, client: Mobilerun) -> None:
+ action = client.devices.actions.global_(
+ device_id="deviceId",
+ action=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_global(self, client: Mobilerun) -> None:
+ response = client.devices.actions.with_raw_response.global_(
+ device_id="deviceId",
+ action=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_global(self, client: Mobilerun) -> None:
+ with client.devices.actions.with_streaming_response.global_(
+ device_id="deviceId",
+ action=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_global(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.actions.with_raw_response.global_(
+ device_id="",
+ action=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_swipe(self, client: Mobilerun) -> None:
+ action = client.devices.actions.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_swipe_with_all_params(self, client: Mobilerun) -> None:
+ action = client.devices.actions.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_swipe(self, client: Mobilerun) -> None:
+ response = client.devices.actions.with_raw_response.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_swipe(self, client: Mobilerun) -> None:
+ with client.devices.actions.with_streaming_response.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_swipe(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.actions.with_raw_response.swipe(
+ device_id="",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_tap(self, client: Mobilerun) -> None:
+ action = client.devices.actions.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_tap_with_all_params(self, client: Mobilerun) -> None:
+ action = client.devices.actions.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_tap(self, client: Mobilerun) -> None:
+ response = client.devices.actions.with_raw_response.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_tap(self, client: Mobilerun) -> None:
+ with client.devices.actions.with_streaming_response.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_tap(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.actions.with_raw_response.tap(
+ device_id="",
+ x=0,
+ y=0,
+ )
+
+
+class TestAsyncActions:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_global(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.global_(
+ device_id="deviceId",
+ action=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_global_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.global_(
+ device_id="deviceId",
+ action=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_global(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.actions.with_raw_response.global_(
+ device_id="deviceId",
+ action=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = await response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_global(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.actions.with_streaming_response.global_(
+ device_id="deviceId",
+ action=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = await response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_global(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.actions.with_raw_response.global_(
+ device_id="",
+ action=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_swipe(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_swipe_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_swipe(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.actions.with_raw_response.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = await response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_swipe(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.actions.with_streaming_response.swipe(
+ device_id="deviceId",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = await response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_swipe(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.actions.with_raw_response.swipe(
+ device_id="",
+ duration=10,
+ end_x=0,
+ end_y=0,
+ start_x=0,
+ start_y=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_tap(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_tap_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ action = await async_client.devices.actions.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ x_device_display_id=0,
+ )
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_tap(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.actions.with_raw_response.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ action = await response.parse()
+ assert action is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_tap(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.actions.with_streaming_response.tap(
+ device_id="deviceId",
+ x=0,
+ y=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ action = await response.parse()
+ assert action is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_tap(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.actions.with_raw_response.tap(
+ device_id="",
+ x=0,
+ y=0,
+ )
diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py
new file mode 100644
index 0000000..6469d82
--- /dev/null
+++ b/tests/api_resources/devices/test_apps.py
@@ -0,0 +1,490 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, Optional, cast
+
+import pytest
+
+from mobilerun import Mobilerun, AsyncMobilerun
+from tests.utils import assert_matches_type
+from mobilerun.types.devices import AppListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestApps:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ app = client.devices.apps.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ app = client.devices.apps.list(
+ device_id="deviceId",
+ include_system_apps=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.devices.apps.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.devices.apps.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_list(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.apps.with_raw_response.list(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_delete(self, client: Mobilerun) -> None:
+ app = client.devices.apps.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_delete_with_all_params(self, client: Mobilerun) -> None:
+ app = client.devices.apps.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Mobilerun) -> None:
+ response = client.devices.apps.with_raw_response.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Mobilerun) -> None:
+ with client.devices.apps.with_streaming_response.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_delete(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.apps.with_raw_response.delete(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ client.devices.apps.with_raw_response.delete(
+ package_name="",
+ device_id="deviceId",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_install(self, client: Mobilerun) -> None:
+ app = client.devices.apps.install(
+ device_id="deviceId",
+ package_name="packageName",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_install_with_all_params(self, client: Mobilerun) -> None:
+ app = client.devices.apps.install(
+ device_id="deviceId",
+ package_name="packageName",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_install(self, client: Mobilerun) -> None:
+ response = client.devices.apps.with_raw_response.install(
+ device_id="deviceId",
+ package_name="packageName",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_install(self, client: Mobilerun) -> None:
+ with client.devices.apps.with_streaming_response.install(
+ device_id="deviceId",
+ package_name="packageName",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_install(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.apps.with_raw_response.install(
+ device_id="",
+ package_name="packageName",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_start(self, client: Mobilerun) -> None:
+ app = client.devices.apps.start(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_start_with_all_params(self, client: Mobilerun) -> None:
+ app = client.devices.apps.start(
+ package_name="packageName",
+ device_id="deviceId",
+ activity="activity",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_start(self, client: Mobilerun) -> None:
+ response = client.devices.apps.with_raw_response.start(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_start(self, client: Mobilerun) -> None:
+ with client.devices.apps.with_streaming_response.start(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_start(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.apps.with_raw_response.start(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ client.devices.apps.with_raw_response.start(
+ package_name="",
+ device_id="deviceId",
+ )
+
+
+class TestAsyncApps:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.list(
+ device_id="deviceId",
+ include_system_apps=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.apps.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.apps.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert_matches_type(Optional[AppListResponse], app, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.apps.with_raw_response.list(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_delete_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.apps.with_raw_response.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.apps.with_streaming_response.delete(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.apps.with_raw_response.delete(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ await async_client.devices.apps.with_raw_response.delete(
+ package_name="",
+ device_id="deviceId",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_install(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.install(
+ device_id="deviceId",
+ package_name="packageName",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_install_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.install(
+ device_id="deviceId",
+ package_name="packageName",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_install(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.apps.with_raw_response.install(
+ device_id="deviceId",
+ package_name="packageName",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_install(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.apps.with_streaming_response.install(
+ device_id="deviceId",
+ package_name="packageName",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_install(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.apps.with_raw_response.install(
+ device_id="",
+ package_name="packageName",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_start(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.start(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_start_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.start(
+ package_name="packageName",
+ device_id="deviceId",
+ activity="activity",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_start(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.apps.with_raw_response.start(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_start(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.apps.with_streaming_response.start(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_start(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.apps.with_raw_response.start(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ await async_client.devices.apps.with_raw_response.start(
+ package_name="",
+ device_id="deviceId",
+ )
diff --git a/tests/api_resources/devices/test_keyboard.py b/tests/api_resources/devices/test_keyboard.py
new file mode 100644
index 0000000..0b329c3
--- /dev/null
+++ b/tests/api_resources/devices/test_keyboard.py
@@ -0,0 +1,358 @@
+# 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 mobilerun import Mobilerun, AsyncMobilerun
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestKeyboard:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_clear(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.clear(
+ device_id="deviceId",
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_clear_with_all_params(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.clear(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_clear(self, client: Mobilerun) -> None:
+ response = client.devices.keyboard.with_raw_response.clear(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_clear(self, client: Mobilerun) -> None:
+ with client.devices.keyboard.with_streaming_response.clear(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_clear(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.keyboard.with_raw_response.clear(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_key(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.key(
+ device_id="deviceId",
+ key=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_key_with_all_params(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.key(
+ device_id="deviceId",
+ key=0,
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_key(self, client: Mobilerun) -> None:
+ response = client.devices.keyboard.with_raw_response.key(
+ device_id="deviceId",
+ key=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_key(self, client: Mobilerun) -> None:
+ with client.devices.keyboard.with_streaming_response.key(
+ device_id="deviceId",
+ key=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_key(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.keyboard.with_raw_response.key(
+ device_id="",
+ key=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_write(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_write_with_all_params(self, client: Mobilerun) -> None:
+ keyboard = client.devices.keyboard.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_write(self, client: Mobilerun) -> None:
+ response = client.devices.keyboard.with_raw_response.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_write(self, client: Mobilerun) -> None:
+ with client.devices.keyboard.with_streaming_response.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_write(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.keyboard.with_raw_response.write(
+ device_id="",
+ clear=True,
+ text="text",
+ )
+
+
+class TestAsyncKeyboard:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_clear(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.clear(
+ device_id="deviceId",
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_clear_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.clear(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_clear(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.keyboard.with_raw_response.clear(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_clear(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.keyboard.with_streaming_response.clear(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_clear(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.keyboard.with_raw_response.clear(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_key(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.key(
+ device_id="deviceId",
+ key=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_key_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.key(
+ device_id="deviceId",
+ key=0,
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_key(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.keyboard.with_raw_response.key(
+ device_id="deviceId",
+ key=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_key(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.keyboard.with_streaming_response.key(
+ device_id="deviceId",
+ key=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_key(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.keyboard.with_raw_response.key(
+ device_id="",
+ key=0,
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_write(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_write_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ keyboard = await async_client.devices.keyboard.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ x_device_display_id=0,
+ )
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_write(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.keyboard.with_raw_response.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_write(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.keyboard.with_streaming_response.write(
+ device_id="deviceId",
+ clear=True,
+ text="text",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ keyboard = await response.parse()
+ assert keyboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_write(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.keyboard.with_raw_response.write(
+ device_id="",
+ clear=True,
+ text="text",
+ )
diff --git a/tests/api_resources/devices/test_packages.py b/tests/api_resources/devices/test_packages.py
new file mode 100644
index 0000000..1a02296
--- /dev/null
+++ b/tests/api_resources/devices/test_packages.py
@@ -0,0 +1,128 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, Optional, cast
+
+import pytest
+
+from mobilerun import Mobilerun, AsyncMobilerun
+from tests.utils import assert_matches_type
+from mobilerun.types.devices import PackageListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestPackages:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ package = client.devices.packages.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ package = client.devices.packages.list(
+ device_id="deviceId",
+ include_system_packages=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.devices.packages.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ package = response.parse()
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.devices.packages.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ package = response.parse()
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_list(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.packages.with_raw_response.list(
+ device_id="",
+ )
+
+
+class TestAsyncPackages:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ package = await async_client.devices.packages.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ package = await async_client.devices.packages.list(
+ device_id="deviceId",
+ include_system_packages=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.packages.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ package = await response.parse()
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.packages.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ package = await response.parse()
+ assert_matches_type(Optional[PackageListResponse], package, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.packages.with_raw_response.list(
+ device_id="",
+ )
diff --git a/tests/api_resources/devices/test_state.py b/tests/api_resources/devices/test_state.py
new file mode 100644
index 0000000..27879b7
--- /dev/null
+++ b/tests/api_resources/devices/test_state.py
@@ -0,0 +1,336 @@
+# 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 mobilerun import Mobilerun, AsyncMobilerun
+from tests.utils import assert_matches_type
+from mobilerun.types.devices import (
+ StateUiResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestState:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_screenshot(self, client: Mobilerun) -> None:
+ state = client.devices.state.screenshot(
+ device_id="deviceId",
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_screenshot_with_all_params(self, client: Mobilerun) -> None:
+ state = client.devices.state.screenshot(
+ device_id="deviceId",
+ hide_overlay=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_screenshot(self, client: Mobilerun) -> None:
+ response = client.devices.state.with_raw_response.screenshot(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_screenshot(self, client: Mobilerun) -> None:
+ with client.devices.state.with_streaming_response.screenshot(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_screenshot(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.state.with_raw_response.screenshot(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_time(self, client: Mobilerun) -> None:
+ state = client.devices.state.time(
+ device_id="deviceId",
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_time_with_all_params(self, client: Mobilerun) -> None:
+ state = client.devices.state.time(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_time(self, client: Mobilerun) -> None:
+ response = client.devices.state.with_raw_response.time(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_time(self, client: Mobilerun) -> None:
+ with client.devices.state.with_streaming_response.time(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_time(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.state.with_raw_response.time(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_ui(self, client: Mobilerun) -> None:
+ state = client.devices.state.ui(
+ device_id="deviceId",
+ )
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_ui_with_all_params(self, client: Mobilerun) -> None:
+ state = client.devices.state.ui(
+ device_id="deviceId",
+ filter=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_ui(self, client: Mobilerun) -> None:
+ response = client.devices.state.with_raw_response.ui(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = response.parse()
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_ui(self, client: Mobilerun) -> None:
+ with client.devices.state.with_streaming_response.ui(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = response.parse()
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_ui(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.state.with_raw_response.ui(
+ device_id="",
+ )
+
+
+class TestAsyncState:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_screenshot(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.screenshot(
+ device_id="deviceId",
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_screenshot_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.screenshot(
+ device_id="deviceId",
+ hide_overlay=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_screenshot(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.state.with_raw_response.screenshot(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = await response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_screenshot(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.state.with_streaming_response.screenshot(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = await response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_screenshot(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.state.with_raw_response.screenshot(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_time(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.time(
+ device_id="deviceId",
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_time_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.time(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_time(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.state.with_raw_response.time(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = await response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_time(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.state.with_streaming_response.time(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = await response.parse()
+ assert_matches_type(str, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_time(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.state.with_raw_response.time(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_ui(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.ui(
+ device_id="deviceId",
+ )
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_ui_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ state = await async_client.devices.state.ui(
+ device_id="deviceId",
+ filter=True,
+ x_device_display_id=0,
+ )
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_ui(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.state.with_raw_response.ui(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = await response.parse()
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_ui(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.state.with_streaming_response.ui(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = await response.parse()
+ assert_matches_type(StateUiResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_ui(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.state.with_raw_response.ui(
+ device_id="",
+ )
diff --git a/tests/api_resources/devices/test_tasks.py b/tests/api_resources/devices/test_tasks.py
new file mode 100644
index 0000000..0b41b32
--- /dev/null
+++ b/tests/api_resources/devices/test_tasks.py
@@ -0,0 +1,132 @@
+# 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 mobilerun import Mobilerun, AsyncMobilerun
+from tests.utils import assert_matches_type
+from mobilerun.types.devices import TaskListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestTasks:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ task = client.devices.tasks.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ task = client.devices.tasks.list(
+ device_id="deviceId",
+ order_by="id",
+ order_by_direction="asc",
+ page=0,
+ page_size=0,
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.devices.tasks.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.devices.tasks.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_list(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.tasks.with_raw_response.list(
+ device_id="",
+ )
+
+
+class TestAsyncTasks:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ task = await async_client.devices.tasks.list(
+ device_id="deviceId",
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ task = await async_client.devices.tasks.list(
+ device_id="deviceId",
+ order_by="id",
+ order_by_direction="asc",
+ page=0,
+ page_size=0,
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.tasks.with_raw_response.list(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = await response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.tasks.with_streaming_response.list(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = await response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.tasks.with_raw_response.list(
+ device_id="",
+ )
diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py
new file mode 100644
index 0000000..f762064
--- /dev/null
+++ b/tests/api_resources/test_devices.py
@@ -0,0 +1,514 @@
+# 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 mobilerun import Mobilerun, AsyncMobilerun
+from tests.utils import assert_matches_type
+from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestDevices:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create(self, client: Mobilerun) -> None:
+ device = client.devices.create()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
+ device = client.devices.create(
+ device_type="device_slot",
+ provider="limrun",
+ apps=["string"],
+ country="country",
+ files=["string"],
+ name="name",
+ proxy={
+ "host": "host",
+ "password": "password",
+ "port": 0,
+ "user": "user",
+ },
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_retrieve(self, client: Mobilerun) -> None:
+ device = client.devices.retrieve(
+ "deviceId",
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.retrieve(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.retrieve(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_retrieve(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ device = client.devices.list()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ device = client.devices.list(
+ country="country",
+ name="name",
+ order_by="id",
+ order_by_direction="asc",
+ page=0,
+ page_size=0,
+ provider="limrun",
+ state="creating",
+ type="device_slot",
+ )
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_count(self, client: Mobilerun) -> None:
+ device = client.devices.count()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_count(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.count()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_count(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.count() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_terminate(self, client: Mobilerun) -> None:
+ device = client.devices.terminate(
+ "deviceId",
+ )
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_terminate(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.terminate(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_terminate(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.terminate(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert device is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_terminate(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.with_raw_response.terminate(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_wait_ready(self, client: Mobilerun) -> None:
+ device = client.devices.wait_ready(
+ "deviceId",
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_wait_ready(self, client: Mobilerun) -> None:
+ response = client.devices.with_raw_response.wait_ready(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_wait_ready(self, client: Mobilerun) -> None:
+ with client.devices.with_streaming_response.wait_ready(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_wait_ready(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.with_raw_response.wait_ready(
+ "",
+ )
+
+
+class TestAsyncDevices:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.create()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.create(
+ device_type="device_slot",
+ provider="limrun",
+ apps=["string"],
+ country="country",
+ files=["string"],
+ name="name",
+ proxy={
+ "host": "host",
+ "password": "password",
+ "port": 0,
+ "user": "user",
+ },
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.retrieve(
+ "deviceId",
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.retrieve(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.retrieve(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.with_raw_response.retrieve(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.list()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.list(
+ country="country",
+ name="name",
+ order_by="id",
+ order_by_direction="asc",
+ page=0,
+ page_size=0,
+ provider="limrun",
+ state="creating",
+ type="device_slot",
+ )
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(DeviceListResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_count(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.count()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_count(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.count()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_count(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.count() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(DeviceCountResponse, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_terminate(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.terminate(
+ "deviceId",
+ )
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_terminate(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.terminate(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_terminate(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.terminate(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert device is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_terminate(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.with_raw_response.terminate(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_wait_ready(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.wait_ready(
+ "deviceId",
+ )
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_wait_ready(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.with_raw_response.wait_ready(
+ "deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_wait_ready(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.with_streaming_response.wait_ready(
+ "deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ device = await response.parse()
+ assert_matches_type(Device, device, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_wait_ready(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.with_raw_response.wait_ready(
+ "",
+ )
From e42aa5309759f931ceab3eee40792e559f21d3a3 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 15 Jan 2026 15:28:50 +0000
Subject: [PATCH 05/25] feat(api): api update
---
.stats.yml | 4 ++--
src/mobilerun/types/llm_model.py | 4 +++-
tests/api_resources/test_tasks.py | 32 +++++++++++++++----------------
3 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index abeefba..b917ab0 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-b3dca99ca43851c1e9adbb78ad6a8a5841cf0b559bf66663c947c41e8635901e.yml
-openapi_spec_hash: 50964e3f8e40873dcb0a768a7fdf855d
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-c7491cf4c81d979b97d7f40aba9ff49675eae88e04d567b0cd93101c00db3492.yml
+openapi_spec_hash: a7db36b93ff62b223eb738a6f51f5e09
config_hash: d1f61f26938ee3af50fa5f703318307d
diff --git a/src/mobilerun/types/llm_model.py b/src/mobilerun/types/llm_model.py
index b42bc72..f0a0dca 100644
--- a/src/mobilerun/types/llm_model.py
+++ b/src/mobilerun/types/llm_model.py
@@ -5,9 +5,11 @@
__all__ = ["LlmModel"]
LlmModel: TypeAlias = Literal[
- "openai/gpt-5",
+ "openai/gpt-5.1",
+ "openai/gpt-5.2",
"google/gemini-2.5-flash",
"google/gemini-2.5-pro",
+ "google/gemini-3-flash",
"google/gemini-3-pro-preview",
"anthropic/claude-sonnet-4.5",
"minimax/minimax-m2",
diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py
index d14af58..2a19e53 100644
--- a/tests/api_resources/test_tasks.py
+++ b/tests/api_resources/test_tasks.py
@@ -237,7 +237,7 @@ def test_path_params_get_trajectory(self, client: Mobilerun) -> None:
@parametrize
def test_method_run(self, client: Mobilerun) -> None:
task = client.tasks.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
assert_matches_type(TaskRunResponse, task, path=["response"])
@@ -246,7 +246,7 @@ def test_method_run(self, client: Mobilerun) -> None:
@parametrize
def test_method_run_with_all_params(self, client: Mobilerun) -> None:
task = client.tasks.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
apps=["string"],
credentials=[
@@ -272,7 +272,7 @@ def test_method_run_with_all_params(self, client: Mobilerun) -> None:
@parametrize
def test_raw_response_run(self, client: Mobilerun) -> None:
response = client.tasks.with_raw_response.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
@@ -285,7 +285,7 @@ def test_raw_response_run(self, client: Mobilerun) -> None:
@parametrize
def test_streaming_response_run(self, client: Mobilerun) -> None:
with client.tasks.with_streaming_response.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
) as response:
assert not response.is_closed
@@ -300,7 +300,7 @@ def test_streaming_response_run(self, client: Mobilerun) -> None:
@parametrize
def test_method_run_streamed(self, client: Mobilerun) -> None:
task = client.tasks.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
assert task is None
@@ -309,7 +309,7 @@ def test_method_run_streamed(self, client: Mobilerun) -> None:
@parametrize
def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None:
task = client.tasks.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
apps=["string"],
credentials=[
@@ -335,7 +335,7 @@ def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None:
@parametrize
def test_raw_response_run_streamed(self, client: Mobilerun) -> None:
response = client.tasks.with_raw_response.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
@@ -348,7 +348,7 @@ def test_raw_response_run_streamed(self, client: Mobilerun) -> None:
@parametrize
def test_streaming_response_run_streamed(self, client: Mobilerun) -> None:
with client.tasks.with_streaming_response.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
) as response:
assert not response.is_closed
@@ -620,7 +620,7 @@ async def test_path_params_get_trajectory(self, async_client: AsyncMobilerun) ->
@parametrize
async def test_method_run(self, async_client: AsyncMobilerun) -> None:
task = await async_client.tasks.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
assert_matches_type(TaskRunResponse, task, path=["response"])
@@ -629,7 +629,7 @@ async def test_method_run(self, async_client: AsyncMobilerun) -> None:
@parametrize
async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) -> None:
task = await async_client.tasks.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
apps=["string"],
credentials=[
@@ -655,7 +655,7 @@ async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) ->
@parametrize
async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
response = await async_client.tasks.with_raw_response.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
@@ -668,7 +668,7 @@ async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
@parametrize
async def test_streaming_response_run(self, async_client: AsyncMobilerun) -> None:
async with async_client.tasks.with_streaming_response.run(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
) as response:
assert not response.is_closed
@@ -683,7 +683,7 @@ async def test_streaming_response_run(self, async_client: AsyncMobilerun) -> Non
@parametrize
async def test_method_run_streamed(self, async_client: AsyncMobilerun) -> None:
task = await async_client.tasks.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
assert task is None
@@ -692,7 +692,7 @@ async def test_method_run_streamed(self, async_client: AsyncMobilerun) -> None:
@parametrize
async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobilerun) -> None:
task = await async_client.tasks.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
apps=["string"],
credentials=[
@@ -718,7 +718,7 @@ async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobi
@parametrize
async def test_raw_response_run_streamed(self, async_client: AsyncMobilerun) -> None:
response = await async_client.tasks.with_raw_response.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
)
@@ -731,7 +731,7 @@ async def test_raw_response_run_streamed(self, async_client: AsyncMobilerun) ->
@parametrize
async def test_streaming_response_run_streamed(self, async_client: AsyncMobilerun) -> None:
async with async_client.tasks.with_streaming_response.run_streamed(
- llm_model="openai/gpt-5",
+ llm_model="openai/gpt-5.1",
task="x",
) as response:
assert not response.is_closed
From 099c2892e8aa33c0f7ec9d7c1d843d3050efb155 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 16 Jan 2026 17:28:54 +0000
Subject: [PATCH 06/25] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index b917ab0..4e28a5c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-c7491cf4c81d979b97d7f40aba9ff49675eae88e04d567b0cd93101c00db3492.yml
-openapi_spec_hash: a7db36b93ff62b223eb738a6f51f5e09
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-e8819bf716fbe8dea79c4ba0056ac76ab711d1aa647205fb45f39e4c7f90e154.yml
+openapi_spec_hash: c9f6063a93c55a53c90775686976ff0e
config_hash: d1f61f26938ee3af50fa5f703318307d
From 75af377b29fca57b52843186af3e9775bfc78c13 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 17 Jan 2026 07:31:49 +0000
Subject: [PATCH 07/25] chore(internal): update `actions/checkout` version
---
.github/workflows/ci.yml | 6 +++---
.github/workflows/publish-pypi.yml | 2 +-
.github/workflows/release-doctor.yml | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e5dc504..9b49e67 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/droidrun-cloud-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Install Rye
run: |
@@ -44,7 +44,7 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/droidrun-cloud-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Install Rye
run: |
@@ -81,7 +81,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/droidrun-cloud-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Install Rye
run: |
diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml
index 33be2b4..965bfe5 100644
--- a/.github/workflows/publish-pypi.yml
+++ b/.github/workflows/publish-pypi.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Install Rye
run: |
diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml
index 66b9372..9f5c3c4 100644
--- a/.github/workflows/release-doctor.yml
+++ b/.github/workflows/release-doctor.yml
@@ -12,7 +12,7 @@ jobs:
if: github.repository == 'droidrun/mobilerun-sdk-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Check release environment
run: |
From bb822b02b08820aef23154468945101df3b9b3a8 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 17 Jan 2026 09:42:11 +0000
Subject: [PATCH 08/25] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index 4e28a5c..dfa5d3a 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-e8819bf716fbe8dea79c4ba0056ac76ab711d1aa647205fb45f39e4c7f90e154.yml
openapi_spec_hash: c9f6063a93c55a53c90775686976ff0e
-config_hash: d1f61f26938ee3af50fa5f703318307d
+config_hash: e86cf4289cfec730125313d2222d09e8
From 678264c95364ad4fff7c70b61bd4794819f28292 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 19 Jan 2026 16:28:36 +0000
Subject: [PATCH 09/25] feat(api): api update
---
.stats.yml | 4 +-
api.md | 2 +-
src/mobilerun/resources/tasks/tasks.py | 102 +------------------------
src/mobilerun/types/__init__.py | 1 -
src/mobilerun/types/task_run_params.py | 52 -------------
tests/api_resources/test_tasks.py | 82 ++------------------
6 files changed, 12 insertions(+), 231 deletions(-)
delete mode 100644 src/mobilerun/types/task_run_params.py
diff --git a/.stats.yml b/.stats.yml
index dfa5d3a..15d9546 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-e8819bf716fbe8dea79c4ba0056ac76ab711d1aa647205fb45f39e4c7f90e154.yml
-openapi_spec_hash: c9f6063a93c55a53c90775686976ff0e
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-ae29ab2212af152dcd463c735f0797b4ce99d43a9535aca3da4d406c881332b1.yml
+openapi_spec_hash: 46915814e9a50b6958a997551ca790c8
config_hash: e86cf4289cfec730125313d2222d09e8
diff --git a/api.md b/api.md
index 0d58a6a..dc69b81 100644
--- a/api.md
+++ b/api.md
@@ -24,7 +24,7 @@ Methods:
- client.tasks.attach(task_id) -> None
- client.tasks.get_status(task_id) -> TaskGetStatusResponse
- client.tasks.get_trajectory(task_id) -> TaskGetTrajectoryResponse
-- client.tasks.run(\*\*params) -> TaskRunResponse
+- client.tasks.run() -> TaskRunResponse
- client.tasks.run_streamed(\*\*params) -> None
- client.tasks.stop(task_id) -> TaskStopResponse
diff --git a/src/mobilerun/resources/tasks/tasks.py b/src/mobilerun/resources/tasks/tasks.py
index 73debb6..be44133 100644
--- a/src/mobilerun/resources/tasks/tasks.py
+++ b/src/mobilerun/resources/tasks/tasks.py
@@ -7,7 +7,7 @@
import httpx
-from ...types import LlmModel, TaskStatus, task_run_params, task_list_params, task_run_streamed_params
+from ...types import LlmModel, TaskStatus, task_list_params, task_run_streamed_params
from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
from ..._utils import maybe_transform, async_maybe_transform
from ..._compat import cached_property
@@ -270,20 +270,6 @@ def get_trajectory(
def run(
self,
*,
- llm_model: LlmModel,
- task: str,
- apps: SequenceNotStr[str] | Omit = omit,
- credentials: Iterable[task_run_params.Credential] | Omit = omit,
- device_id: Optional[str] | Omit = omit,
- display_id: int | Omit = omit,
- execution_timeout: int | Omit = omit,
- files: SequenceNotStr[str] | Omit = omit,
- max_steps: int | Omit = omit,
- output_schema: Optional[Dict[str, object]] | Omit = omit,
- reasoning: bool | Omit = omit,
- temperature: float | Omit = omit,
- vision: bool | Omit = omit,
- vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
# 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,
@@ -291,43 +277,9 @@ def run(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> TaskRunResponse:
- """
- Run Task
-
- Args:
- device_id: The ID of the device to run the task on.
-
- display_id: The display ID of the device to run the task on.
-
- 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
- """
+ """Run Task"""
return self._post(
"/tasks/",
- body=maybe_transform(
- {
- "llm_model": llm_model,
- "task": task,
- "apps": apps,
- "credentials": credentials,
- "device_id": device_id,
- "display_id": display_id,
- "execution_timeout": execution_timeout,
- "files": files,
- "max_steps": max_steps,
- "output_schema": output_schema,
- "reasoning": reasoning,
- "temperature": temperature,
- "vision": vision,
- "vpn_country": vpn_country,
- },
- task_run_params.TaskRunParams,
- ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -659,20 +611,6 @@ async def get_trajectory(
async def run(
self,
*,
- llm_model: LlmModel,
- task: str,
- apps: SequenceNotStr[str] | Omit = omit,
- credentials: Iterable[task_run_params.Credential] | Omit = omit,
- device_id: Optional[str] | Omit = omit,
- display_id: int | Omit = omit,
- execution_timeout: int | Omit = omit,
- files: SequenceNotStr[str] | Omit = omit,
- max_steps: int | Omit = omit,
- output_schema: Optional[Dict[str, object]] | Omit = omit,
- reasoning: bool | Omit = omit,
- temperature: float | Omit = omit,
- vision: bool | Omit = omit,
- vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
# 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,
@@ -680,43 +618,9 @@ async def run(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> TaskRunResponse:
- """
- Run Task
-
- Args:
- device_id: The ID of the device to run the task on.
-
- display_id: The display ID of the device to run the task on.
-
- 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
- """
+ """Run Task"""
return await self._post(
"/tasks/",
- body=await async_maybe_transform(
- {
- "llm_model": llm_model,
- "task": task,
- "apps": apps,
- "credentials": credentials,
- "device_id": device_id,
- "display_id": display_id,
- "execution_timeout": execution_timeout,
- "files": files,
- "max_steps": max_steps,
- "output_schema": output_schema,
- "reasoning": reasoning,
- "temperature": temperature,
- "vision": vision,
- "vpn_country": vpn_country,
- },
- task_run_params.TaskRunParams,
- ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index 72eddf4..59932b1 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -7,7 +7,6 @@
from .llm_model import LlmModel as LlmModel
from .task_status import TaskStatus as TaskStatus
from .app_list_params import AppListParams as AppListParams
-from .task_run_params import TaskRunParams as TaskRunParams
from .hook_list_params import HookListParams as HookListParams
from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
diff --git a/src/mobilerun/types/task_run_params.py b/src/mobilerun/types/task_run_params.py
deleted file mode 100644
index 81389c6..0000000
--- a/src/mobilerun/types/task_run_params.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Dict, Iterable, Optional
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-from .llm_model import LlmModel
-
-__all__ = ["TaskRunParams", "Credential"]
-
-
-class TaskRunParams(TypedDict, total=False):
- llm_model: Required[Annotated[LlmModel, PropertyInfo(alias="llmModel")]]
-
- task: Required[str]
-
- apps: SequenceNotStr[str]
-
- credentials: Iterable[Credential]
-
- device_id: Annotated[Optional[str], PropertyInfo(alias="deviceId")]
- """The ID of the device to run the task on."""
-
- display_id: Annotated[int, PropertyInfo(alias="displayId")]
- """The display ID of the device to run the task on."""
-
- execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")]
-
- files: SequenceNotStr[str]
-
- max_steps: Annotated[int, PropertyInfo(alias="maxSteps")]
-
- output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")]
-
- reasoning: bool
-
- temperature: float
-
- vision: bool
-
- vpn_country: Annotated[
- Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]], PropertyInfo(alias="vpnCountry")
- ]
-
-
-class Credential(TypedDict, total=False):
- credential_names: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="credentialNames")]]
-
- package_name: Required[Annotated[str, PropertyInfo(alias="packageName")]]
diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py
index 2a19e53..eede77a 100644
--- a/tests/api_resources/test_tasks.py
+++ b/tests/api_resources/test_tasks.py
@@ -236,45 +236,13 @@ def test_path_params_get_trajectory(self, client: Mobilerun) -> None:
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_run(self, client: Mobilerun) -> None:
- task = client.tasks.run(
- llm_model="openai/gpt-5.1",
- task="x",
- )
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_run_with_all_params(self, client: Mobilerun) -> None:
- task = client.tasks.run(
- llm_model="openai/gpt-5.1",
- task="x",
- apps=["string"],
- credentials=[
- {
- "credential_names": ["string"],
- "package_name": "packageName",
- }
- ],
- device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- display_id=0,
- execution_timeout=0,
- files=["string"],
- max_steps=0,
- output_schema={"foo": "bar"},
- reasoning=True,
- temperature=0,
- vision=True,
- vpn_country="US",
- )
+ task = client.tasks.run()
assert_matches_type(TaskRunResponse, task, path=["response"])
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_raw_response_run(self, client: Mobilerun) -> None:
- response = client.tasks.with_raw_response.run(
- llm_model="openai/gpt-5.1",
- task="x",
- )
+ response = client.tasks.with_raw_response.run()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -284,10 +252,7 @@ def test_raw_response_run(self, client: Mobilerun) -> None:
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_streaming_response_run(self, client: Mobilerun) -> None:
- with client.tasks.with_streaming_response.run(
- llm_model="openai/gpt-5.1",
- task="x",
- ) as response:
+ with client.tasks.with_streaming_response.run() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -619,45 +584,13 @@ async def test_path_params_get_trajectory(self, async_client: AsyncMobilerun) ->
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_run(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.run(
- llm_model="openai/gpt-5.1",
- task="x",
- )
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.run(
- llm_model="openai/gpt-5.1",
- task="x",
- apps=["string"],
- credentials=[
- {
- "credential_names": ["string"],
- "package_name": "packageName",
- }
- ],
- device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- display_id=0,
- execution_timeout=0,
- files=["string"],
- max_steps=0,
- output_schema={"foo": "bar"},
- reasoning=True,
- temperature=0,
- vision=True,
- vpn_country="US",
- )
+ task = await async_client.tasks.run()
assert_matches_type(TaskRunResponse, task, path=["response"])
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.tasks.with_raw_response.run(
- llm_model="openai/gpt-5.1",
- task="x",
- )
+ response = await async_client.tasks.with_raw_response.run()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -667,10 +600,7 @@ async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_streaming_response_run(self, async_client: AsyncMobilerun) -> None:
- async with async_client.tasks.with_streaming_response.run(
- llm_model="openai/gpt-5.1",
- task="x",
- ) as response:
+ async with async_client.tasks.with_streaming_response.run() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
From 00033ad7ffac1d3d650a05e841bbdecca964192e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Sat, 24 Jan 2026 06:30:00 +0000
Subject: [PATCH 10/25] chore(ci): upgrade `actions/github-script`
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9b49e67..d721fb5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -63,7 +63,7 @@ jobs:
- name: Get GitHub OIDC Token
if: github.repository == 'stainless-sdks/droidrun-cloud-python'
id: github-oidc
- uses: actions/github-script@v6
+ uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());
From 8d53e63fd8ccebbe5a77af740cd5e6bdf85c2a85 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 27 Jan 2026 15:28:44 +0000
Subject: [PATCH 11/25] feat(api): api update
---
.stats.yml | 4 +-
api.md | 4 +-
.../resources/credentials/credentials.py | 58 +++++++++++++++++--
src/mobilerun/resources/devices/devices.py | 23 +++++++-
src/mobilerun/types/__init__.py | 2 +
src/mobilerun/types/credential_list_params.py | 15 +++++
.../types/credential_list_response.py | 22 ++++++-
src/mobilerun/types/device.py | 2 +
src/mobilerun/types/device_count_response.py | 20 +------
.../types/device_terminate_params.py | 17 ++++++
tests/api_resources/test_credentials.py | 18 ++++++
tests/api_resources/test_devices.py | 43 +++++++++++---
12 files changed, 189 insertions(+), 39 deletions(-)
create mode 100644 src/mobilerun/types/credential_list_params.py
create mode 100644 src/mobilerun/types/device_terminate_params.py
diff --git a/.stats.yml b/.stats.yml
index 15d9546..8a5e297 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-ae29ab2212af152dcd463c735f0797b4ce99d43a9535aca3da4d406c881332b1.yml
-openapi_spec_hash: 46915814e9a50b6958a997551ca790c8
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-4bf8f98a9401a23c28c58ffa490a8e694c0270e6afcbca96893bbdcd2297bab0.yml
+openapi_spec_hash: f7c043febb06730a8049f1b07170d209
config_hash: e86cf4289cfec730125313d2222d09e8
diff --git a/api.md b/api.md
index dc69b81..312c8b8 100644
--- a/api.md
+++ b/api.md
@@ -68,7 +68,7 @@ Methods:
- client.devices.retrieve(device_id) -> Device
- client.devices.list(\*\*params) -> DeviceListResponse
- client.devices.count() -> DeviceCountResponse
-- client.devices.terminate(device_id) -> None
+- client.devices.terminate(device_id, \*\*params) -> None
- client.devices.wait_ready(device_id) -> Device
## Actions
@@ -162,7 +162,7 @@ from mobilerun.types import CredentialListResponse
Methods:
-- client.credentials.list() -> CredentialListResponse
+- client.credentials.list(\*\*params) -> CredentialListResponse
## Packages
diff --git a/src/mobilerun/resources/credentials/credentials.py b/src/mobilerun/resources/credentials/credentials.py
index 3bf9957..43d30f4 100644
--- a/src/mobilerun/resources/credentials/credentials.py
+++ b/src/mobilerun/resources/credentials/credentials.py
@@ -4,7 +4,9 @@
import httpx
-from ..._types import Body, Query, Headers, NotGiven, not_given
+from ...types import credential_list_params
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -54,6 +56,8 @@ def with_streaming_response(self) -> CredentialsResourceWithStreamingResponse:
def list(
self,
*,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
# 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,
@@ -61,11 +65,32 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> CredentialListResponse:
- """List all credentials for the authenticated user"""
+ """
+ List all credentials for the authenticated user
+
+ 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
+ """
return self._get(
"/credentials",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "page": page,
+ "page_size": page_size,
+ },
+ credential_list_params.CredentialListParams,
+ ),
),
cast_to=CredentialListResponse,
)
@@ -98,6 +123,8 @@ def with_streaming_response(self) -> AsyncCredentialsResourceWithStreamingRespon
async def list(
self,
*,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
# 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,
@@ -105,11 +132,32 @@ async def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> CredentialListResponse:
- """List all credentials for the authenticated user"""
+ """
+ List all credentials for the authenticated user
+
+ 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
+ """
return await self._get(
"/credentials",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "page": page,
+ "page_size": page_size,
+ },
+ credential_list_params.CredentialListParams,
+ ),
),
cast_to=CredentialListResponse,
)
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
index 63be619..98d1b0b 100644
--- a/src/mobilerun/resources/devices/devices.py
+++ b/src/mobilerun/resources/devices/devices.py
@@ -2,7 +2,8 @@
from __future__ import annotations
-from typing import Optional
+from typing import Union, Optional
+from datetime import datetime
from typing_extensions import Literal
import httpx
@@ -31,7 +32,7 @@
TasksResourceWithStreamingResponse,
AsyncTasksResourceWithStreamingResponse,
)
-from ...types import device_list_params, device_create_params
+from ...types import device_list_params, device_create_params, device_terminate_params
from .actions import (
ActionsResource,
AsyncActionsResource,
@@ -287,6 +288,8 @@ def terminate(
self,
device_id: str,
*,
+ previous_device_id: str | Omit = omit,
+ terminate_at: Union[str, datetime] | Omit = omit,
# 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,
@@ -311,6 +314,13 @@ def terminate(
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return self._delete(
f"/devices/{device_id}",
+ body=maybe_transform(
+ {
+ "previous_device_id": previous_device_id,
+ "terminate_at": terminate_at,
+ },
+ device_terminate_params.DeviceTerminateParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -564,6 +574,8 @@ async def terminate(
self,
device_id: str,
*,
+ previous_device_id: str | Omit = omit,
+ terminate_at: Union[str, datetime] | Omit = omit,
# 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,
@@ -588,6 +600,13 @@ async def terminate(
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return await self._delete(
f"/devices/{device_id}",
+ body=await async_maybe_transform(
+ {
+ "previous_device_id": previous_device_id,
+ "terminate_at": terminate_at,
+ },
+ device_terminate_params.DeviceTerminateParams,
+ ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index 59932b1..1ce0ebb 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -22,8 +22,10 @@
from .device_count_response import DeviceCountResponse as DeviceCountResponse
from .hook_perform_response import HookPerformResponse as HookPerformResponse
from .hook_subscribe_params import HookSubscribeParams as HookSubscribeParams
+from .credential_list_params import CredentialListParams as CredentialListParams
from .hook_retrieve_response import HookRetrieveResponse as HookRetrieveResponse
from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse
+from .device_terminate_params import DeviceTerminateParams as DeviceTerminateParams
from .hook_subscribe_response import HookSubscribeResponse as HookSubscribeResponse
from .credential_list_response import CredentialListResponse as CredentialListResponse
from .task_get_status_response import TaskGetStatusResponse as TaskGetStatusResponse
diff --git a/src/mobilerun/types/credential_list_params.py b/src/mobilerun/types/credential_list_params.py
new file mode 100644
index 0000000..1f94a2e
--- /dev/null
+++ b/src/mobilerun/types/credential_list_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["CredentialListParams"]
+
+
+class CredentialListParams(TypedDict, total=False):
+ page: int
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun/types/credential_list_response.py b/src/mobilerun/types/credential_list_response.py
index ec43392..b558f15 100644
--- a/src/mobilerun/types/credential_list_response.py
+++ b/src/mobilerun/types/credential_list_response.py
@@ -2,11 +2,29 @@
from typing import List
+from pydantic import Field as FieldInfo
+
from .._models import BaseModel
from .credentials.packages.credential import Credential
-__all__ = ["CredentialListResponse"]
+__all__ = ["CredentialListResponse", "Pagination"]
+
+
+class Pagination(BaseModel):
+ has_next: bool = FieldInfo(alias="hasNext")
+
+ has_prev: bool = FieldInfo(alias="hasPrev")
+
+ page: int
+
+ pages: int
+
+ page_size: int = FieldInfo(alias="pageSize")
+
+ total: int
class CredentialListResponse(BaseModel):
- data: List[Credential]
+ items: List[Credential]
+
+ pagination: Pagination
diff --git a/src/mobilerun/types/device.py b/src/mobilerun/types/device.py
index 3d570c1..9abc6c6 100644
--- a/src/mobilerun/types/device.py
+++ b/src/mobilerun/types/device.py
@@ -39,6 +39,8 @@ class Device(BaseModel):
task_count: int = FieldInfo(alias="taskCount")
+ terminates_at: Optional[datetime] = FieldInfo(alias="terminatesAt", default=None)
+
updated_at: datetime = FieldInfo(alias="updatedAt")
schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
diff --git a/src/mobilerun/types/device_count_response.py b/src/mobilerun/types/device_count_response.py
index 517cdeb..966ff68 100644
--- a/src/mobilerun/types/device_count_response.py
+++ b/src/mobilerun/types/device_count_response.py
@@ -1,22 +1,8 @@
# 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
+from typing import Dict
+from typing_extensions import TypeAlias
__all__ = ["DeviceCountResponse"]
-
-class DeviceCountResponse(BaseModel):
- limrun: int
-
- personal: int
-
- remote: int
-
- roidrun: int
-
- schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
- """A URL to the JSON Schema for this object."""
+DeviceCountResponse: TypeAlias = Dict[str, int]
diff --git a/src/mobilerun/types/device_terminate_params.py b/src/mobilerun/types/device_terminate_params.py
new file mode 100644
index 0000000..f4a7660
--- /dev/null
+++ b/src/mobilerun/types/device_terminate_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union
+from datetime import datetime
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["DeviceTerminateParams"]
+
+
+class DeviceTerminateParams(TypedDict, total=False):
+ previous_device_id: Annotated[str, PropertyInfo(alias="previousDeviceId")]
+
+ terminate_at: Annotated[Union[str, datetime], PropertyInfo(alias="terminateAt", format="iso8601")]
diff --git a/tests/api_resources/test_credentials.py b/tests/api_resources/test_credentials.py
index b488c4c..ae068c0 100644
--- a/tests/api_resources/test_credentials.py
+++ b/tests/api_resources/test_credentials.py
@@ -23,6 +23,15 @@ def test_method_list(self, client: Mobilerun) -> None:
credential = client.credentials.list()
assert_matches_type(CredentialListResponse, credential, path=["response"])
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ credential = client.credentials.list(
+ page=1,
+ page_size=1,
+ )
+ assert_matches_type(CredentialListResponse, credential, path=["response"])
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_raw_response_list(self, client: Mobilerun) -> None:
@@ -57,6 +66,15 @@ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
credential = await async_client.credentials.list()
assert_matches_type(CredentialListResponse, credential, path=["response"])
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ credential = await async_client.credentials.list(
+ page=1,
+ page_size=1,
+ )
+ assert_matches_type(CredentialListResponse, credential, path=["response"])
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py
index f762064..70d181f 100644
--- a/tests/api_resources/test_devices.py
+++ b/tests/api_resources/test_devices.py
@@ -9,7 +9,12 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
-from mobilerun.types import Device, DeviceListResponse, DeviceCountResponse
+from mobilerun.types import (
+ Device,
+ DeviceListResponse,
+ DeviceCountResponse,
+)
+from mobilerun._utils import parse_datetime
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -182,7 +187,17 @@ def test_streaming_response_count(self, client: Mobilerun) -> None:
@parametrize
def test_method_terminate(self, client: Mobilerun) -> None:
device = client.devices.terminate(
- "deviceId",
+ device_id="deviceId",
+ )
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_terminate_with_all_params(self, client: Mobilerun) -> None:
+ device = client.devices.terminate(
+ device_id="deviceId",
+ previous_device_id="previousDeviceId",
+ terminate_at=parse_datetime("2019-12-27T18:11:19.117Z"),
)
assert device is None
@@ -190,7 +205,7 @@ def test_method_terminate(self, client: Mobilerun) -> None:
@parametrize
def test_raw_response_terminate(self, client: Mobilerun) -> None:
response = client.devices.with_raw_response.terminate(
- "deviceId",
+ device_id="deviceId",
)
assert response.is_closed is True
@@ -202,7 +217,7 @@ def test_raw_response_terminate(self, client: Mobilerun) -> None:
@parametrize
def test_streaming_response_terminate(self, client: Mobilerun) -> None:
with client.devices.with_streaming_response.terminate(
- "deviceId",
+ device_id="deviceId",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -217,7 +232,7 @@ def test_streaming_response_terminate(self, client: Mobilerun) -> None:
def test_path_params_terminate(self, client: Mobilerun) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
client.devices.with_raw_response.terminate(
- "",
+ device_id="",
)
@pytest.mark.skip(reason="Prism tests are disabled")
@@ -433,7 +448,17 @@ async def test_streaming_response_count(self, async_client: AsyncMobilerun) -> N
@parametrize
async def test_method_terminate(self, async_client: AsyncMobilerun) -> None:
device = await async_client.devices.terminate(
- "deviceId",
+ device_id="deviceId",
+ )
+ assert device is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_terminate_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ device = await async_client.devices.terminate(
+ device_id="deviceId",
+ previous_device_id="previousDeviceId",
+ terminate_at=parse_datetime("2019-12-27T18:11:19.117Z"),
)
assert device is None
@@ -441,7 +466,7 @@ async def test_method_terminate(self, async_client: AsyncMobilerun) -> None:
@parametrize
async def test_raw_response_terminate(self, async_client: AsyncMobilerun) -> None:
response = await async_client.devices.with_raw_response.terminate(
- "deviceId",
+ device_id="deviceId",
)
assert response.is_closed is True
@@ -453,7 +478,7 @@ async def test_raw_response_terminate(self, async_client: AsyncMobilerun) -> Non
@parametrize
async def test_streaming_response_terminate(self, async_client: AsyncMobilerun) -> None:
async with async_client.devices.with_streaming_response.terminate(
- "deviceId",
+ device_id="deviceId",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -468,7 +493,7 @@ async def test_streaming_response_terminate(self, async_client: AsyncMobilerun)
async def test_path_params_terminate(self, async_client: AsyncMobilerun) -> None:
with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
await async_client.devices.with_raw_response.terminate(
- "",
+ device_id="",
)
@pytest.mark.skip(reason="Prism tests are disabled")
From a1864da1fa55aae682b63d3d36c41919cecc48dd Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 27 Jan 2026 19:28:27 +0000
Subject: [PATCH 12/25] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 8a5e297..b649ee3 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-4bf8f98a9401a23c28c58ffa490a8e694c0270e6afcbca96893bbdcd2297bab0.yml
-openapi_spec_hash: f7c043febb06730a8049f1b07170d209
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-91aa5c667f9ee1e16d1b24cc1ba16089159815161b808224ebaa38d3c81e4441.yml
+openapi_spec_hash: 18ac37d22714f5d727f3d6a3b859a3fb
config_hash: e86cf4289cfec730125313d2222d09e8
From 4c2d97de0a1ae482871912fe677ed64e0919825e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 28 Jan 2026 11:28:24 +0000
Subject: [PATCH 13/25] feat(api): api update
---
.stats.yml | 4 ++--
src/mobilerun/resources/devices/devices.py | 14 ++++++++++----
src/mobilerun/types/device_create_params.py | 4 ++--
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index b649ee3..8f178e9 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-91aa5c667f9ee1e16d1b24cc1ba16089159815161b808224ebaa38d3c81e4441.yml
-openapi_spec_hash: 18ac37d22714f5d727f3d6a3b859a3fb
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-b8be3b35a75a443348bfd1b33f118bdbf0f2b5666043f82702ce9e231e291659.yml
+openapi_spec_hash: 038b3bb350a54776c97d491e2547f03c
config_hash: e86cf4289cfec730125313d2222d09e8
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
index 98d1b0b..9242980 100644
--- a/src/mobilerun/resources/devices/devices.py
+++ b/src/mobilerun/resources/devices/devices.py
@@ -122,8 +122,11 @@ def with_streaming_response(self) -> DevicesResourceWithStreamingResponse:
def create(
self,
*,
- device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
+ device_type: Literal[
+ "device_slot", "dedicated_emulated_device", "dedicated_physical_device", "dedicated_premium_device"
+ ]
+ | Omit = omit,
+ provider: Literal["limrun", "physical", "premium", "roidrun"] | Omit = omit,
apps: Optional[SequenceNotStr[str]] | Omit = omit,
country: str | Omit = omit,
files: Optional[SequenceNotStr[str]] | Omit = omit,
@@ -408,8 +411,11 @@ def with_streaming_response(self) -> AsyncDevicesResourceWithStreamingResponse:
async def create(
self,
*,
- device_type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
- provider: Literal["limrun", "remote", "roidrun"] | Omit = omit,
+ device_type: Literal[
+ "device_slot", "dedicated_emulated_device", "dedicated_physical_device", "dedicated_premium_device"
+ ]
+ | Omit = omit,
+ provider: Literal["limrun", "physical", "premium", "roidrun"] | Omit = omit,
apps: Optional[SequenceNotStr[str]] | Omit = omit,
country: str | Omit = omit,
files: Optional[SequenceNotStr[str]] | Omit = omit,
diff --git a/src/mobilerun/types/device_create_params.py b/src/mobilerun/types/device_create_params.py
index 4134f5a..6539a3b 100644
--- a/src/mobilerun/types/device_create_params.py
+++ b/src/mobilerun/types/device_create_params.py
@@ -13,11 +13,11 @@
class DeviceCreateParams(TypedDict, total=False):
device_type: Annotated[
- Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"],
+ Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device", "dedicated_premium_device"],
PropertyInfo(alias="deviceType"),
]
- provider: Literal["limrun", "remote", "roidrun"]
+ provider: Literal["limrun", "physical", "premium", "roidrun"]
apps: Optional[SequenceNotStr[str]]
From a06f4b2146dafd2c9435fecb603a6217b085fcc5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 29 Jan 2026 07:10:33 +0000
Subject: [PATCH 14/25] fix(docs): fix mcp installation instructions for remote
servers
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 0eece63..fd577f2 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,8 @@ It is generated with [Stainless](https://www.stainless.com/).
Use the Mobilerun MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
-[](https://cursor.com/en-US/install-mcp?name=mobilerun-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1vYmlsZXJ1bi1tY3AiXX0)
-[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22mobilerun-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mobilerun-mcp%22%5D%7D)
+[](https://cursor.com/en-US/install-mcp?name=mobilerun-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1vYmlsZXJ1bi1tY3AiXSwiZW52Ijp7Ik1PQklMRVJVTl9DTE9VRF9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)
+[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22mobilerun-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mobilerun-mcp%22%5D%2C%22env%22%3A%7B%22MOBILERUN_CLOUD_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)
> Note: You may need to set environment variables in your MCP client.
From 947195285cae03d555b21716015384cc2e1f3fa0 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 30 Jan 2026 06:13:45 +0000
Subject: [PATCH 15/25] feat(client): add custom JSON encoder for extended type
support
---
src/mobilerun/_base_client.py | 7 +-
src/mobilerun/_compat.py | 6 +-
src/mobilerun/_utils/_json.py | 35 ++++++++++
tests/test_utils/test_json.py | 126 ++++++++++++++++++++++++++++++++++
4 files changed, 169 insertions(+), 5 deletions(-)
create mode 100644 src/mobilerun/_utils/_json.py
create mode 100644 tests/test_utils/test_json.py
diff --git a/src/mobilerun/_base_client.py b/src/mobilerun/_base_client.py
index 5177829..19e64c7 100644
--- a/src/mobilerun/_base_client.py
+++ b/src/mobilerun/_base_client.py
@@ -86,6 +86,7 @@
APIConnectionError,
APIResponseValidationError,
)
+from ._utils._json import openapi_dumps
log: logging.Logger = logging.getLogger(__name__)
@@ -554,8 +555,10 @@ def _build_request(
kwargs["content"] = options.content
elif isinstance(json_data, bytes):
kwargs["content"] = json_data
- else:
- kwargs["json"] = json_data if is_given(json_data) else None
+ elif not files:
+ # Don't set content when JSON is sent as multipart/form-data,
+ # since httpx's content param overrides other body arguments
+ kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None
kwargs["files"] = files
else:
headers.pop("Content-Type", None)
diff --git a/src/mobilerun/_compat.py b/src/mobilerun/_compat.py
index bdef67f..786ff42 100644
--- a/src/mobilerun/_compat.py
+++ b/src/mobilerun/_compat.py
@@ -139,6 +139,7 @@ def model_dump(
exclude_defaults: bool = False,
warnings: bool = True,
mode: Literal["json", "python"] = "python",
+ by_alias: bool | None = None,
) -> dict[str, Any]:
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
return model.model_dump(
@@ -148,13 +149,12 @@ def model_dump(
exclude_defaults=exclude_defaults,
# warnings are not supported in Pydantic v1
warnings=True if PYDANTIC_V1 else warnings,
+ by_alias=by_alias,
)
return cast(
"dict[str, Any]",
model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
- exclude=exclude,
- exclude_unset=exclude_unset,
- exclude_defaults=exclude_defaults,
+ exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
),
)
diff --git a/src/mobilerun/_utils/_json.py b/src/mobilerun/_utils/_json.py
new file mode 100644
index 0000000..6058421
--- /dev/null
+++ b/src/mobilerun/_utils/_json.py
@@ -0,0 +1,35 @@
+import json
+from typing import Any
+from datetime import datetime
+from typing_extensions import override
+
+import pydantic
+
+from .._compat import model_dump
+
+
+def openapi_dumps(obj: Any) -> bytes:
+ """
+ Serialize an object to UTF-8 encoded JSON bytes.
+
+ Extends the standard json.dumps with support for additional types
+ commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc.
+ """
+ return json.dumps(
+ obj,
+ cls=_CustomEncoder,
+ # Uses the same defaults as httpx's JSON serialization
+ ensure_ascii=False,
+ separators=(",", ":"),
+ allow_nan=False,
+ ).encode()
+
+
+class _CustomEncoder(json.JSONEncoder):
+ @override
+ def default(self, o: Any) -> Any:
+ if isinstance(o, datetime):
+ return o.isoformat()
+ if isinstance(o, pydantic.BaseModel):
+ return model_dump(o, exclude_unset=True, mode="json", by_alias=True)
+ return super().default(o)
diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py
new file mode 100644
index 0000000..837420f
--- /dev/null
+++ b/tests/test_utils/test_json.py
@@ -0,0 +1,126 @@
+from __future__ import annotations
+
+import datetime
+from typing import Union
+
+import pydantic
+
+from mobilerun import _compat
+from mobilerun._utils._json import openapi_dumps
+
+
+class TestOpenapiDumps:
+ def test_basic(self) -> None:
+ data = {"key": "value", "number": 42}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"key":"value","number":42}'
+
+ def test_datetime_serialization(self) -> None:
+ dt = datetime.datetime(2023, 1, 1, 12, 0, 0)
+ data = {"datetime": dt}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}'
+
+ def test_pydantic_model_serialization(self) -> None:
+ class User(pydantic.BaseModel):
+ first_name: str
+ last_name: str
+ age: int
+
+ model_instance = User(first_name="John", last_name="Kramer", age=83)
+ data = {"model": model_instance}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}'
+
+ def test_pydantic_model_with_default_values(self) -> None:
+ class User(pydantic.BaseModel):
+ name: str
+ role: str = "user"
+ active: bool = True
+ score: int = 0
+
+ model_instance = User(name="Alice")
+ data = {"model": model_instance}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"name":"Alice"}}'
+
+ def test_pydantic_model_with_default_values_overridden(self) -> None:
+ class User(pydantic.BaseModel):
+ name: str
+ role: str = "user"
+ active: bool = True
+
+ model_instance = User(name="Bob", role="admin", active=False)
+ data = {"model": model_instance}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}'
+
+ def test_pydantic_model_with_alias(self) -> None:
+ class User(pydantic.BaseModel):
+ first_name: str = pydantic.Field(alias="firstName")
+ last_name: str = pydantic.Field(alias="lastName")
+
+ model_instance = User(firstName="John", lastName="Doe")
+ data = {"model": model_instance}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}'
+
+ def test_pydantic_model_with_alias_and_default(self) -> None:
+ class User(pydantic.BaseModel):
+ user_name: str = pydantic.Field(alias="userName")
+ user_role: str = pydantic.Field(default="member", alias="userRole")
+ is_active: bool = pydantic.Field(default=True, alias="isActive")
+
+ model_instance = User(userName="charlie")
+ data = {"model": model_instance}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"userName":"charlie"}}'
+
+ model_with_overrides = User(userName="diana", userRole="admin", isActive=False)
+ data = {"model": model_with_overrides}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}'
+
+ def test_pydantic_model_with_nested_models_and_defaults(self) -> None:
+ class Address(pydantic.BaseModel):
+ street: str
+ city: str = "Unknown"
+
+ class User(pydantic.BaseModel):
+ name: str
+ address: Address
+ verified: bool = False
+
+ if _compat.PYDANTIC_V1:
+ # to handle forward references in Pydantic v1
+ User.update_forward_refs(**locals()) # type: ignore[reportDeprecated]
+
+ address = Address(street="123 Main St")
+ user = User(name="Diana", address=address)
+ data = {"user": user}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}'
+
+ address_with_city = Address(street="456 Oak Ave", city="Boston")
+ user_verified = User(name="Eve", address=address_with_city, verified=True)
+ data = {"user": user_verified}
+ json_bytes = openapi_dumps(data)
+ assert (
+ json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}'
+ )
+
+ def test_pydantic_model_with_optional_fields(self) -> None:
+ class User(pydantic.BaseModel):
+ name: str
+ email: Union[str, None]
+ phone: Union[str, None]
+
+ model_with_none = User(name="Eve", email=None, phone=None)
+ data = {"model": model_with_none}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}'
+
+ model_with_values = User(name="Frank", email="frank@example.com", phone=None)
+ data = {"model": model_with_values}
+ json_bytes = openapi_dumps(data)
+ assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}'
From 2dc1d4cc2e6b4fc6f19f3e18d9d0e660caa675c4 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 30 Jan 2026 11:57:07 +0000
Subject: [PATCH 16/25] codegen metadata
---
.stats.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.stats.yml b/.stats.yml
index 8f178e9..23797e4 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-b8be3b35a75a443348bfd1b33f118bdbf0f2b5666043f82702ce9e231e291659.yml
openapi_spec_hash: 038b3bb350a54776c97d491e2547f03c
-config_hash: e86cf4289cfec730125313d2222d09e8
+config_hash: 97b79867ce1dca69c6872bcea77574fb
From 91ab0631121c4ca096133953344ea83e96cc32ae Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 10 Feb 2026 06:25:55 +0000
Subject: [PATCH 17/25] chore(internal): bump dependencies
---
requirements-dev.lock | 20 ++++++++++----------
requirements.lock | 8 ++++----
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/requirements-dev.lock b/requirements-dev.lock
index 49213b4..bd2a014 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -12,14 +12,14 @@
-e file:.
aiohappyeyeballs==2.6.1
# via aiohttp
-aiohttp==3.13.2
+aiohttp==3.13.3
# via httpx-aiohttp
# via mobilerun-sdk
aiosignal==1.4.0
# via aiohttp
annotated-types==0.7.0
# via pydantic
-anyio==4.12.0
+anyio==4.12.1
# via httpx
# via mobilerun-sdk
argcomplete==3.6.3
@@ -31,7 +31,7 @@ attrs==25.4.0
# via nox
backports-asyncio-runner==1.2.0
# via pytest-asyncio
-certifi==2025.11.12
+certifi==2026.1.4
# via httpcore
# via httpx
colorlog==6.10.1
@@ -61,7 +61,7 @@ httpx==0.28.1
# via httpx-aiohttp
# via mobilerun-sdk
# via respx
-httpx-aiohttp==0.1.9
+httpx-aiohttp==0.1.12
# via mobilerun-sdk
humanize==4.13.0
# via nox
@@ -69,7 +69,7 @@ idna==3.11
# via anyio
# via httpx
# via yarl
-importlib-metadata==8.7.0
+importlib-metadata==8.7.1
iniconfig==2.1.0
# via pytest
markdown-it-py==3.0.0
@@ -82,14 +82,14 @@ multidict==6.7.0
mypy==1.17.0
mypy-extensions==1.1.0
# via mypy
-nodeenv==1.9.1
+nodeenv==1.10.0
# via pyright
nox==2025.11.12
packaging==25.0
# via dependency-groups
# via nox
# via pytest
-pathspec==0.12.1
+pathspec==1.0.3
# via mypy
platformdirs==4.4.0
# via virtualenv
@@ -115,13 +115,13 @@ python-dateutil==2.9.0.post0
# via time-machine
respx==0.22.0
rich==14.2.0
-ruff==0.14.7
+ruff==0.14.13
six==1.17.0
# via python-dateutil
sniffio==1.3.1
# via mobilerun-sdk
time-machine==2.19.0
-tomli==2.3.0
+tomli==2.4.0
# via dependency-groups
# via mypy
# via nox
@@ -141,7 +141,7 @@ typing-extensions==4.15.0
# via virtualenv
typing-inspection==0.4.2
# via pydantic
-virtualenv==20.35.4
+virtualenv==20.36.1
# via nox
yarl==1.22.0
# via aiohttp
diff --git a/requirements.lock b/requirements.lock
index 17e9b83..5c59b39 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -12,21 +12,21 @@
-e file:.
aiohappyeyeballs==2.6.1
# via aiohttp
-aiohttp==3.13.2
+aiohttp==3.13.3
# via httpx-aiohttp
# via mobilerun-sdk
aiosignal==1.4.0
# via aiohttp
annotated-types==0.7.0
# via pydantic
-anyio==4.12.0
+anyio==4.12.1
# via httpx
# via mobilerun-sdk
async-timeout==5.0.1
# via aiohttp
attrs==25.4.0
# via aiohttp
-certifi==2025.11.12
+certifi==2026.1.4
# via httpcore
# via httpx
distro==1.9.0
@@ -43,7 +43,7 @@ httpcore==1.0.9
httpx==0.28.1
# via httpx-aiohttp
# via mobilerun-sdk
-httpx-aiohttp==0.1.9
+httpx-aiohttp==0.1.12
# via mobilerun-sdk
idna==3.11
# via anyio
From f5920bc46fb52360860c02ca941926e939f3e316 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 12 Feb 2026 08:18:40 +0000
Subject: [PATCH 18/25] chore(internal): fix lint error on Python 3.14
---
src/mobilerun/_utils/_compat.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mobilerun/_utils/_compat.py b/src/mobilerun/_utils/_compat.py
index dd70323..2c70b29 100644
--- a/src/mobilerun/_utils/_compat.py
+++ b/src/mobilerun/_utils/_compat.py
@@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool:
else:
import types
- return tp is Union or tp is types.UnionType
+ return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap]
def is_typeddict(tp: Type[Any]) -> bool:
From 2910e4312fa6360f754de4d6937d677cd04acc68 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 13 Feb 2026 05:23:16 +0000
Subject: [PATCH 19/25] chore: format all `api.md` files
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 4874197..3984f67 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -69,7 +69,7 @@ format = { chain = [
# run formatting again to fix any inconsistencies when imports are stripped
"format:ruff",
]}
-"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md"
+"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'"
"format:ruff" = "ruff format"
"lint" = { chain = [
From 9049554b1ab39ca164a3351861ec41c9ea78d489 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 16 Feb 2026 18:24:34 +0000
Subject: [PATCH 20/25] feat(api): api update
---
.stats.yml | 4 ++--
src/mobilerun/resources/devices/devices.py | 8 +++++---
src/mobilerun/types/app_list_response.py | 10 ++++++----
src/mobilerun/types/device_list_params.py | 3 ++-
tests/api_resources/test_devices.py | 4 ++--
5 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 23797e4..77b87f1 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-b8be3b35a75a443348bfd1b33f118bdbf0f2b5666043f82702ce9e231e291659.yml
-openapi_spec_hash: 038b3bb350a54776c97d491e2547f03c
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-7d0a0e2531657fe9adce4dc0ebdfb0b3d04f582f35b6b4a7e3cfc6fc11ab1f14.yml
+openapi_spec_hash: 8ddbfd253e75226ede884b92e5c8fbe7
config_hash: 97b79867ce1dca69c6872bcea77574fb
diff --git a/src/mobilerun/resources/devices/devices.py b/src/mobilerun/resources/devices/devices.py
index 9242980..22936d9 100644
--- a/src/mobilerun/resources/devices/devices.py
+++ b/src/mobilerun/resources/devices/devices.py
@@ -2,7 +2,7 @@
from __future__ import annotations
-from typing import Union, Optional
+from typing import List, Union, Optional
from datetime import datetime
from typing_extensions import Literal
@@ -222,7 +222,8 @@ def list(
page: int | Omit = omit,
page_size: int | Omit = omit,
provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
+ state: Optional[List[Literal["creating", "assigned", "ready", "disconnected", "terminated", "unknown"]]]
+ | Omit = omit,
type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
# 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.
@@ -511,7 +512,8 @@ async def list(
page: int | Omit = omit,
page_size: int | Omit = omit,
provider: Literal["limrun", "personal", "remote", "roidrun"] | Omit = omit,
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"] | Omit = omit,
+ state: Optional[List[Literal["creating", "assigned", "ready", "disconnected", "terminated", "unknown"]]]
+ | Omit = omit,
type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"] | Omit = omit,
# 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.
diff --git a/src/mobilerun/types/app_list_response.py b/src/mobilerun/types/app_list_response.py
index 8ddc700..2a928f8 100644
--- a/src/mobilerun/types/app_list_response.py
+++ b/src/mobilerun/types/app_list_response.py
@@ -1,7 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import List, Optional
-from datetime import date
+from datetime import datetime
from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -285,7 +285,7 @@ class Item(BaseModel):
]
] = None
- created_at: Optional[date] = FieldInfo(alias="createdAt", default=None)
+ created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
description: Optional[str] = None
@@ -299,7 +299,9 @@ class Item(BaseModel):
package_name: str = FieldInfo(alias="packageName")
- queued_at: Optional[date] = FieldInfo(alias="queuedAt", default=None)
+ privacy_policy_url: Optional[str] = FieldInfo(alias="privacyPolicyUrl", default=None)
+
+ queued_at: Optional[datetime] = FieldInfo(alias="queuedAt", default=None)
rating_count: Optional[int] = FieldInfo(alias="ratingCount", default=None)
@@ -311,7 +313,7 @@ class Item(BaseModel):
target_sdk: Optional[int] = FieldInfo(alias="targetSdk", default=None)
- updated_at: Optional[date] = FieldInfo(alias="updatedAt", default=None)
+ updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
user_id: Optional[str] = FieldInfo(alias="userId", default=None)
diff --git a/src/mobilerun/types/device_list_params.py b/src/mobilerun/types/device_list_params.py
index 48b5c7f..2e1503a 100644
--- a/src/mobilerun/types/device_list_params.py
+++ b/src/mobilerun/types/device_list_params.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from typing import List, Optional
from typing_extensions import Literal, Annotated, TypedDict
from .._utils import PropertyInfo
@@ -24,6 +25,6 @@ class DeviceListParams(TypedDict, total=False):
provider: Literal["limrun", "personal", "remote", "roidrun"]
- state: Literal["creating", "assigned", "ready", "terminated", "unknown"]
+ state: Optional[List[Literal["creating", "assigned", "ready", "disconnected", "terminated", "unknown"]]]
type: Literal["device_slot", "dedicated_emulated_device", "dedicated_physical_device"]
diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py
index 70d181f..b60998a 100644
--- a/tests/api_resources/test_devices.py
+++ b/tests/api_resources/test_devices.py
@@ -128,7 +128,7 @@ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
page=0,
page_size=0,
provider="limrun",
- state="creating",
+ state=["creating"],
type="device_slot",
)
assert_matches_type(DeviceListResponse, device, path=["response"])
@@ -389,7 +389,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -
page=0,
page_size=0,
provider="limrun",
- state="creating",
+ state=["creating"],
type="device_slot",
)
assert_matches_type(DeviceListResponse, device, path=["response"])
From 543bbd877819b2dc23ecfe5b3d4722996b54e92b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Mon, 16 Feb 2026 21:24:32 +0000
Subject: [PATCH 21/25] feat(api): api update
---
.stats.yml | 6 +-
README.md | 54 ++--
api.md | 9 +-
src/mobilerun/resources/hooks.py | 108 +------
src/mobilerun/resources/tasks/tasks.py | 299 +-----------------
src/mobilerun/types/__init__.py | 6 -
src/mobilerun/types/hook_list_params.py | 20 --
src/mobilerun/types/hook_list_response.py | 60 ----
src/mobilerun/types/task.py | 6 +
.../types/task_get_trajectory_response.py | 23 +-
src/mobilerun/types/task_list_params.py | 28 --
src/mobilerun/types/task_list_response.py | 40 ---
src/mobilerun/types/task_run_response.py | 18 --
.../types/task_run_streamed_params.py | 52 ---
tests/api_resources/test_hooks.py | 79 -----
tests/api_resources/test_tasks.py | 229 +-------------
tests/test_client.py | 56 ++--
17 files changed, 114 insertions(+), 979 deletions(-)
delete mode 100644 src/mobilerun/types/hook_list_params.py
delete mode 100644 src/mobilerun/types/hook_list_response.py
delete mode 100644 src/mobilerun/types/task_list_params.py
delete mode 100644 src/mobilerun/types/task_list_response.py
delete mode 100644 src/mobilerun/types/task_run_response.py
delete mode 100644 src/mobilerun/types/task_run_streamed_params.py
diff --git a/.stats.yml b/.stats.yml
index 77b87f1..39d3be5 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 50
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-7d0a0e2531657fe9adce4dc0ebdfb0b3d04f582f35b6b4a7e3cfc6fc11ab1f14.yml
-openapi_spec_hash: 8ddbfd253e75226ede884b92e5c8fbe7
+configured_endpoints: 47
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-825adf3ea9bf2a0f6fca08379e9976d62c50dfc38fa57e6da7710bbf5183a89e.yml
+openapi_spec_hash: a1bf4abae9edb6f6739bce4a1d8c90a4
config_hash: 97b79867ce1dca69c6872bcea77574fb
diff --git a/README.md b/README.md
index fd577f2..927a65b 100644
--- a/README.md
+++ b/README.md
@@ -34,15 +34,14 @@ pip install mobilerun-sdk
The full API of this library can be found in [api.md](api.md).
```python
-import os
from mobilerun import Mobilerun
-client = Mobilerun(
- api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
-)
+client = Mobilerun()
-tasks = client.tasks.list()
-print(tasks.items)
+task = client.tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+)
+print(task.task)
```
While you can provide a `api_key` keyword argument,
@@ -55,18 +54,17 @@ so that your API Key is not stored in source control.
Simply import `AsyncMobilerun` instead of `Mobilerun` and use `await` with each API call:
```python
-import os
import asyncio
from mobilerun import AsyncMobilerun
-client = AsyncMobilerun(
- api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
-)
+client = AsyncMobilerun()
async def main() -> None:
- tasks = await client.tasks.list()
- print(tasks.items)
+ task = await client.tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ print(task.task)
asyncio.run(main())
@@ -88,7 +86,6 @@ pip install mobilerun-sdk[aiohttp]
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
```python
-import os
import asyncio
from mobilerun import DefaultAioHttpClient
from mobilerun import AsyncMobilerun
@@ -96,11 +93,12 @@ from mobilerun import AsyncMobilerun
async def main() -> None:
async with AsyncMobilerun(
- api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
http_client=DefaultAioHttpClient(),
) as client:
- tasks = await client.tasks.list()
- print(tasks.items)
+ task = await client.tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ print(task.task)
asyncio.run(main())
@@ -151,7 +149,9 @@ from mobilerun import Mobilerun
client = Mobilerun()
try:
- client.tasks.list()
+ client.tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
except mobilerun.APIConnectionError as e:
print("The server could not be reached")
print(e.__cause__) # an underlying Exception, likely raised within httpx.
@@ -194,7 +194,9 @@ client = Mobilerun(
)
# Or, configure per-request:
-client.with_options(max_retries=5).tasks.list()
+client.with_options(max_retries=5).tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+)
```
### Timeouts
@@ -217,7 +219,9 @@ client = Mobilerun(
)
# Override per-request:
-client.with_options(timeout=5.0).tasks.list()
+client.with_options(timeout=5.0).tasks.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+)
```
On timeout, an `APITimeoutError` is thrown.
@@ -258,11 +262,13 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from mobilerun import Mobilerun
client = Mobilerun()
-response = client.tasks.with_raw_response.list()
+response = client.tasks.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+)
print(response.headers.get('X-My-Header'))
-task = response.parse() # get the object that `tasks.list()` would have returned
-print(task.items)
+task = response.parse() # get the object that `tasks.retrieve()` would have returned
+print(task.task)
```
These methods return an [`APIResponse`](https://github.com/droidrun/mobilerun-sdk-python/tree/main/src/mobilerun/_response.py) object.
@@ -276,7 +282,9 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.tasks.with_streaming_response.list() as response:
+with client.tasks.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+) as response:
print(response.headers.get("X-My-Header"))
for line in response.iter_lines():
diff --git a/api.md b/api.md
index 312c8b8..e5c341a 100644
--- a/api.md
+++ b/api.md
@@ -6,13 +6,10 @@ Types:
from mobilerun.types import (
LlmModel,
Task,
- TaskCreate,
TaskStatus,
TaskRetrieveResponse,
- TaskListResponse,
TaskGetStatusResponse,
TaskGetTrajectoryResponse,
- TaskRunResponse,
TaskStopResponse,
)
```
@@ -20,12 +17,10 @@ from mobilerun.types import (
Methods:
- client.tasks.retrieve(task_id) -> TaskRetrieveResponse
-- client.tasks.list(\*\*params) -> TaskListResponse
- client.tasks.attach(task_id) -> None
- client.tasks.get_status(task_id) -> TaskGetStatusResponse
- client.tasks.get_trajectory(task_id) -> TaskGetTrajectoryResponse
-- client.tasks.run() -> TaskRunResponse
-- client.tasks.run_streamed(\*\*params) -> None
+- client.tasks.run_streamed() -> None
- client.tasks.stop(task_id) -> TaskStopResponse
## Screenshots
@@ -222,7 +217,6 @@ Types:
from mobilerun.types import (
HookRetrieveResponse,
HookUpdateResponse,
- HookListResponse,
HookGetSampleDataResponse,
HookPerformResponse,
HookSubscribeResponse,
@@ -234,7 +228,6 @@ Methods:
- client.hooks.retrieve(hook_id) -> HookRetrieveResponse
- client.hooks.update(hook_id, \*\*params) -> HookUpdateResponse
-- client.hooks.list(\*\*params) -> HookListResponse
- client.hooks.get_sample_data() -> HookGetSampleDataResponse
- client.hooks.perform() -> HookPerformResponse
- client.hooks.subscribe(\*\*params) -> HookSubscribeResponse
diff --git a/src/mobilerun/resources/hooks.py b/src/mobilerun/resources/hooks.py
index b410998..25f5c72 100644
--- a/src/mobilerun/resources/hooks.py
+++ b/src/mobilerun/resources/hooks.py
@@ -3,11 +3,10 @@
from __future__ import annotations
from typing import Optional
-from typing_extensions import Literal
import httpx
-from ..types import hook_list_params, hook_update_params, hook_subscribe_params
+from ..types import hook_update_params, hook_subscribe_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -19,7 +18,6 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
-from ..types.hook_list_response import HookListResponse
from ..types.hook_update_response import HookUpdateResponse
from ..types.hook_perform_response import HookPerformResponse
from ..types.hook_retrieve_response import HookRetrieveResponse
@@ -131,52 +129,6 @@ def update(
cast_to=HookUpdateResponse,
)
- def list(
- self,
- *,
- order_by: Optional[str] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # 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,
- ) -> HookListResponse:
- """
- List hooks belonging to the requesting user (paginated).
-
- 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
- """
- return self._get(
- "/hooks/",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- },
- hook_list_params.HookListParams,
- ),
- ),
- cast_to=HookListResponse,
- )
-
def get_sample_data(
self,
*,
@@ -401,52 +353,6 @@ async def update(
cast_to=HookUpdateResponse,
)
- async def list(
- self,
- *,
- order_by: Optional[str] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: int | Omit = omit,
- page_size: int | Omit = omit,
- # 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,
- ) -> HookListResponse:
- """
- List hooks belonging to the requesting user (paginated).
-
- 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
- """
- return await self._get(
- "/hooks/",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- },
- hook_list_params.HookListParams,
- ),
- ),
- cast_to=HookListResponse,
- )
-
async def get_sample_data(
self,
*,
@@ -580,9 +486,6 @@ def __init__(self, hooks: HooksResource) -> None:
self.update = to_raw_response_wrapper(
hooks.update,
)
- self.list = to_raw_response_wrapper(
- hooks.list,
- )
self.get_sample_data = to_raw_response_wrapper(
hooks.get_sample_data,
)
@@ -607,9 +510,6 @@ def __init__(self, hooks: AsyncHooksResource) -> None:
self.update = async_to_raw_response_wrapper(
hooks.update,
)
- self.list = async_to_raw_response_wrapper(
- hooks.list,
- )
self.get_sample_data = async_to_raw_response_wrapper(
hooks.get_sample_data,
)
@@ -634,9 +534,6 @@ def __init__(self, hooks: HooksResource) -> None:
self.update = to_streamed_response_wrapper(
hooks.update,
)
- self.list = to_streamed_response_wrapper(
- hooks.list,
- )
self.get_sample_data = to_streamed_response_wrapper(
hooks.get_sample_data,
)
@@ -661,9 +558,6 @@ def __init__(self, hooks: AsyncHooksResource) -> None:
self.update = async_to_streamed_response_wrapper(
hooks.update,
)
- self.list = async_to_streamed_response_wrapper(
- hooks.list,
- )
self.get_sample_data = async_to_streamed_response_wrapper(
hooks.get_sample_data,
)
diff --git a/src/mobilerun/resources/tasks/tasks.py b/src/mobilerun/resources/tasks/tasks.py
index be44133..c584e49 100644
--- a/src/mobilerun/resources/tasks/tasks.py
+++ b/src/mobilerun/resources/tasks/tasks.py
@@ -2,14 +2,9 @@
from __future__ import annotations
-from typing import Dict, Iterable, Optional
-from typing_extensions import Literal
-
import httpx
-from ...types import LlmModel, TaskStatus, task_list_params, task_run_streamed_params
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given
from ..._compat import cached_property
from .ui_states import (
UiStatesResource,
@@ -35,10 +30,6 @@
AsyncScreenshotsResourceWithStreamingResponse,
)
from ..._base_client import make_request_options
-from ...types.llm_model import LlmModel
-from ...types.task_status import TaskStatus
-from ...types.task_run_response import TaskRunResponse
-from ...types.task_list_response import TaskListResponse
from ...types.task_stop_response import TaskStopResponse
from ...types.task_retrieve_response import TaskRetrieveResponse
from ...types.task_get_status_response import TaskGetStatusResponse
@@ -108,63 +99,6 @@ def retrieve(
cast_to=TaskRetrieveResponse,
)
- def list(
- self,
- *,
- order_by: Optional[Literal["id", "createdAt", "finishedAt", "status"]] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: Optional[int] | Omit = omit,
- page_size: int | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[TaskStatus] | Omit = omit,
- # 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,
- ) -> TaskListResponse:
- """List all tasks you've created so far
-
- Args:
- page: Page number (1-based).
-
- If provided, returns paginated results.
-
- page_size: Number of items per page
-
- query: Search in task description.
-
- 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
- """
- return self._get(
- "/tasks/",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- "query": query,
- "status": status,
- },
- task_list_params.TaskListParams,
- ),
- ),
- cast_to=TaskListResponse,
- )
-
def attach(
self,
task_id: str,
@@ -210,10 +144,8 @@ def get_status(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> TaskGetStatusResponse:
- """Get the status of a task.
-
- If device is provided, return the status of the
- specific device. Otherwise, return the status of all devices.
+ """
+ Get the status of a task.
Args:
extra_headers: Send extra headers
@@ -267,42 +199,9 @@ def get_trajectory(
cast_to=TaskGetTrajectoryResponse,
)
- def run(
- self,
- *,
- # 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,
- ) -> TaskRunResponse:
- """Run Task"""
- return self._post(
- "/tasks/",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=TaskRunResponse,
- )
-
def run_streamed(
self,
*,
- llm_model: LlmModel,
- task: str,
- apps: SequenceNotStr[str] | Omit = omit,
- credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit,
- device_id: Optional[str] | Omit = omit,
- display_id: int | Omit = omit,
- execution_timeout: int | Omit = omit,
- files: SequenceNotStr[str] | Omit = omit,
- max_steps: int | Omit = omit,
- output_schema: Optional[Dict[str, object]] | Omit = omit,
- reasoning: bool | Omit = omit,
- temperature: float | Omit = omit,
- vision: bool | Omit = omit,
- vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
# 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,
@@ -310,44 +209,10 @@ def run_streamed(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
- """
- Run Streamed Task
-
- Args:
- device_id: The ID of the device to run the task on.
-
- display_id: The display ID of the device to run the task on.
-
- 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
- """
+ """Run Streamed Task"""
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return self._post(
"/tasks/stream",
- body=maybe_transform(
- {
- "llm_model": llm_model,
- "task": task,
- "apps": apps,
- "credentials": credentials,
- "device_id": device_id,
- "display_id": display_id,
- "execution_timeout": execution_timeout,
- "files": files,
- "max_steps": max_steps,
- "output_schema": output_schema,
- "reasoning": reasoning,
- "temperature": temperature,
- "vision": vision,
- "vpn_country": vpn_country,
- },
- task_run_streamed_params.TaskRunStreamedParams,
- ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -449,63 +314,6 @@ async def retrieve(
cast_to=TaskRetrieveResponse,
)
- async def list(
- self,
- *,
- order_by: Optional[Literal["id", "createdAt", "finishedAt", "status"]] | Omit = omit,
- order_by_direction: Literal["asc", "desc"] | Omit = omit,
- page: Optional[int] | Omit = omit,
- page_size: int | Omit = omit,
- query: Optional[str] | Omit = omit,
- status: Optional[TaskStatus] | Omit = omit,
- # 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,
- ) -> TaskListResponse:
- """List all tasks you've created so far
-
- Args:
- page: Page number (1-based).
-
- If provided, returns paginated results.
-
- page_size: Number of items per page
-
- query: Search in task description.
-
- 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
- """
- return await self._get(
- "/tasks/",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "order_by": order_by,
- "order_by_direction": order_by_direction,
- "page": page,
- "page_size": page_size,
- "query": query,
- "status": status,
- },
- task_list_params.TaskListParams,
- ),
- ),
- cast_to=TaskListResponse,
- )
-
async def attach(
self,
task_id: str,
@@ -551,10 +359,8 @@ async def get_status(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> TaskGetStatusResponse:
- """Get the status of a task.
-
- If device is provided, return the status of the
- specific device. Otherwise, return the status of all devices.
+ """
+ Get the status of a task.
Args:
extra_headers: Send extra headers
@@ -608,42 +414,9 @@ async def get_trajectory(
cast_to=TaskGetTrajectoryResponse,
)
- async def run(
- self,
- *,
- # 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,
- ) -> TaskRunResponse:
- """Run Task"""
- return await self._post(
- "/tasks/",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=TaskRunResponse,
- )
-
async def run_streamed(
self,
*,
- llm_model: LlmModel,
- task: str,
- apps: SequenceNotStr[str] | Omit = omit,
- credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit,
- device_id: Optional[str] | Omit = omit,
- display_id: int | Omit = omit,
- execution_timeout: int | Omit = omit,
- files: SequenceNotStr[str] | Omit = omit,
- max_steps: int | Omit = omit,
- output_schema: Optional[Dict[str, object]] | Omit = omit,
- reasoning: bool | Omit = omit,
- temperature: float | Omit = omit,
- vision: bool | Omit = omit,
- vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit,
# 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,
@@ -651,44 +424,10 @@ async def run_streamed(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
- """
- Run Streamed Task
-
- Args:
- device_id: The ID of the device to run the task on.
-
- display_id: The display ID of the device to run the task on.
-
- 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
- """
+ """Run Streamed Task"""
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
return await self._post(
"/tasks/stream",
- body=await async_maybe_transform(
- {
- "llm_model": llm_model,
- "task": task,
- "apps": apps,
- "credentials": credentials,
- "device_id": device_id,
- "display_id": display_id,
- "execution_timeout": execution_timeout,
- "files": files,
- "max_steps": max_steps,
- "output_schema": output_schema,
- "reasoning": reasoning,
- "temperature": temperature,
- "vision": vision,
- "vpn_country": vpn_country,
- },
- task_run_streamed_params.TaskRunStreamedParams,
- ),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -736,9 +475,6 @@ def __init__(self, tasks: TasksResource) -> None:
self.retrieve = to_raw_response_wrapper(
tasks.retrieve,
)
- self.list = to_raw_response_wrapper(
- tasks.list,
- )
self.attach = to_raw_response_wrapper(
tasks.attach,
)
@@ -748,9 +484,6 @@ def __init__(self, tasks: TasksResource) -> None:
self.get_trajectory = to_raw_response_wrapper(
tasks.get_trajectory,
)
- self.run = to_raw_response_wrapper(
- tasks.run,
- )
self.run_streamed = to_raw_response_wrapper(
tasks.run_streamed,
)
@@ -774,9 +507,6 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.retrieve = async_to_raw_response_wrapper(
tasks.retrieve,
)
- self.list = async_to_raw_response_wrapper(
- tasks.list,
- )
self.attach = async_to_raw_response_wrapper(
tasks.attach,
)
@@ -786,9 +516,6 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.get_trajectory = async_to_raw_response_wrapper(
tasks.get_trajectory,
)
- self.run = async_to_raw_response_wrapper(
- tasks.run,
- )
self.run_streamed = async_to_raw_response_wrapper(
tasks.run_streamed,
)
@@ -812,9 +539,6 @@ def __init__(self, tasks: TasksResource) -> None:
self.retrieve = to_streamed_response_wrapper(
tasks.retrieve,
)
- self.list = to_streamed_response_wrapper(
- tasks.list,
- )
self.attach = to_streamed_response_wrapper(
tasks.attach,
)
@@ -824,9 +548,6 @@ def __init__(self, tasks: TasksResource) -> None:
self.get_trajectory = to_streamed_response_wrapper(
tasks.get_trajectory,
)
- self.run = to_streamed_response_wrapper(
- tasks.run,
- )
self.run_streamed = to_streamed_response_wrapper(
tasks.run_streamed,
)
@@ -850,9 +571,6 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.retrieve = async_to_streamed_response_wrapper(
tasks.retrieve,
)
- self.list = async_to_streamed_response_wrapper(
- tasks.list,
- )
self.attach = async_to_streamed_response_wrapper(
tasks.attach,
)
@@ -862,9 +580,6 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.get_trajectory = async_to_streamed_response_wrapper(
tasks.get_trajectory,
)
- self.run = async_to_streamed_response_wrapper(
- tasks.run,
- )
self.run_streamed = async_to_streamed_response_wrapper(
tasks.run_streamed,
)
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index 1ce0ebb..c7e41e4 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -7,14 +7,9 @@
from .llm_model import LlmModel as LlmModel
from .task_status import TaskStatus as TaskStatus
from .app_list_params import AppListParams as AppListParams
-from .hook_list_params import HookListParams as HookListParams
-from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
-from .task_run_response import TaskRunResponse as TaskRunResponse
from .device_list_params import DeviceListParams as DeviceListParams
-from .hook_list_response import HookListResponse as HookListResponse
from .hook_update_params import HookUpdateParams as HookUpdateParams
-from .task_list_response import TaskListResponse as TaskListResponse
from .task_stop_response import TaskStopResponse as TaskStopResponse
from .device_create_params import DeviceCreateParams as DeviceCreateParams
from .device_list_response import DeviceListResponse as DeviceListResponse
@@ -29,7 +24,6 @@
from .hook_subscribe_response import HookSubscribeResponse as HookSubscribeResponse
from .credential_list_response import CredentialListResponse as CredentialListResponse
from .task_get_status_response import TaskGetStatusResponse as TaskGetStatusResponse
-from .task_run_streamed_params import TaskRunStreamedParams as TaskRunStreamedParams
from .hook_unsubscribe_response import HookUnsubscribeResponse as HookUnsubscribeResponse
from .task_get_trajectory_response import TaskGetTrajectoryResponse as TaskGetTrajectoryResponse
from .hook_get_sample_data_response import HookGetSampleDataResponse as HookGetSampleDataResponse
diff --git a/src/mobilerun/types/hook_list_params.py b/src/mobilerun/types/hook_list_params.py
deleted file mode 100644
index 5d3fe14..0000000
--- a/src/mobilerun/types/hook_list_params.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["HookListParams"]
-
-
-class HookListParams(TypedDict, total=False):
- order_by: Annotated[Optional[str], PropertyInfo(alias="orderBy")]
-
- order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
-
- page: int
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun/types/hook_list_response.py b/src/mobilerun/types/hook_list_response.py
deleted file mode 100644
index dbc468c..0000000
--- a/src/mobilerun/types/hook_list_response.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-from .task_status import TaskStatus
-
-__all__ = ["HookListResponse", "Item", "Pagination"]
-
-
-class Item(BaseModel):
- service: Literal["zapier", "n8n", "make", "internal", "other"]
-
- url: str
-
- user_id: str = FieldInfo(alias="userId")
-
- id: Optional[str] = None
-
- created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
-
- events: Optional[List[TaskStatus]] = None
-
- state: Optional[Literal["active", "disabled", "deleted"]] = None
-
- updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-
-
-class Pagination(BaseModel):
- """Pagination metadata"""
-
- has_next: bool = FieldInfo(alias="hasNext")
- """Whether there is a next page"""
-
- has_prev: bool = FieldInfo(alias="hasPrev")
- """Whether there is a previous page"""
-
- page: int
- """Current page number (1-based)"""
-
- pages: int
- """Total number of pages"""
-
- page_size: int = FieldInfo(alias="pageSize")
- """Number of items per page"""
-
- total: int
- """Total number of items"""
-
-
-class HookListResponse(BaseModel):
- items: List[Item]
- """The paginated items"""
-
- pagination: Pagination
- """Pagination metadata"""
diff --git a/src/mobilerun/types/task.py b/src/mobilerun/types/task.py
index 0f79671..7b29244 100644
--- a/src/mobilerun/types/task.py
+++ b/src/mobilerun/types/task.py
@@ -36,6 +36,8 @@ class Task(BaseModel):
credentials: Optional[List[Credential]] = None
+ display_id: Optional[int] = FieldInfo(alias="displayId", default=None)
+
execution_timeout: Optional[int] = FieldInfo(alias="executionTimeout", default=None)
files: Optional[List[str]] = None
@@ -50,6 +52,8 @@ class Task(BaseModel):
reasoning: Optional[bool] = None
+ sandbox_id: Optional[str] = FieldInfo(alias="sandboxId", default=None)
+
status: Optional[TaskStatus] = None
steps: Optional[int] = None
@@ -58,6 +62,8 @@ class Task(BaseModel):
temperature: Optional[float] = None
+ tmp_device: Optional[bool] = FieldInfo(alias="tmpDevice", default=None)
+
trajectory: Optional[List[Dict[str, object]]] = None
updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
diff --git a/src/mobilerun/types/task_get_trajectory_response.py b/src/mobilerun/types/task_get_trajectory_response.py
index cac5d6f..e11150e 100644
--- a/src/mobilerun/types/task_get_trajectory_response.py
+++ b/src/mobilerun/types/task_get_trajectory_response.py
@@ -23,6 +23,7 @@
"TrajectoryTrajectoryFinalizeEventData",
"TrajectoryTrajectoryStopEvent",
"TrajectoryTrajectoryResultEvent",
+ "TrajectoryTrajectoryResultEventData",
"TrajectoryTrajectoryManagerInputEvent",
"TrajectoryTrajectoryManagerPlanEvent",
"TrajectoryTrajectoryManagerPlanEventData",
@@ -192,8 +193,28 @@ async def my_step(self, ctx: Context, ev: StartEvent) -> MyStopEv:
event: Literal["StopEvent"]
+class TrajectoryTrajectoryResultEventData(BaseModel):
+ """Lazy wrapper — avoids importing droidrun at module level.
+
+ The worker uses droidrun's ResultEvent directly; this model only
+ exists so the API OpenAPI schema can reference it without the heavy
+ droidrun import.
+ """
+
+ steps: Optional[int] = None
+
+ structured_output: Union[Dict[str, object], object, None] = None
+
+ success: Optional[bool] = None
+
+
class TrajectoryTrajectoryResultEvent(BaseModel):
- data: Dict[str, object]
+ data: TrajectoryTrajectoryResultEventData
+ """Lazy wrapper — avoids importing droidrun at module level.
+
+ The worker uses droidrun's ResultEvent directly; this model only exists so the
+ API OpenAPI schema can reference it without the heavy droidrun import.
+ """
event: Literal["ResultEvent"]
diff --git a/src/mobilerun/types/task_list_params.py b/src/mobilerun/types/task_list_params.py
deleted file mode 100644
index 08881ad..0000000
--- a/src/mobilerun/types/task_list_params.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Optional
-from typing_extensions import Literal, Annotated, TypedDict
-
-from .._utils import PropertyInfo
-from .task_status import TaskStatus
-
-__all__ = ["TaskListParams"]
-
-
-class TaskListParams(TypedDict, total=False):
- order_by: Annotated[Optional[Literal["id", "createdAt", "finishedAt", "status"]], PropertyInfo(alias="orderBy")]
-
- order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
-
- page: Optional[int]
- """Page number (1-based). If provided, returns paginated results."""
-
- page_size: Annotated[int, PropertyInfo(alias="pageSize")]
- """Number of items per page"""
-
- query: Optional[str]
- """Search in task description."""
-
- status: Optional[TaskStatus]
diff --git a/src/mobilerun/types/task_list_response.py b/src/mobilerun/types/task_list_response.py
deleted file mode 100644
index 0860788..0000000
--- a/src/mobilerun/types/task_list_response.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-
-from pydantic import Field as FieldInfo
-
-from .task import Task
-from .._models import BaseModel
-
-__all__ = ["TaskListResponse", "Pagination"]
-
-
-class Pagination(BaseModel):
- """Pagination metadata"""
-
- has_next: bool = FieldInfo(alias="hasNext")
- """Whether there is a next page"""
-
- has_prev: bool = FieldInfo(alias="hasPrev")
- """Whether there is a previous page"""
-
- page: int
- """Current page number (1-based)"""
-
- pages: int
- """Total number of pages"""
-
- page_size: int = FieldInfo(alias="pageSize")
- """Number of items per page"""
-
- total: int
- """Total number of items"""
-
-
-class TaskListResponse(BaseModel):
- items: List[Task]
- """The paginated items"""
-
- pagination: Pagination
- """Pagination metadata"""
diff --git a/src/mobilerun/types/task_run_response.py b/src/mobilerun/types/task_run_response.py
deleted file mode 100644
index 4e61f59..0000000
--- a/src/mobilerun/types/task_run_response.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["TaskRunResponse"]
-
-
-class TaskRunResponse(BaseModel):
- id: str
- """The ID of the task"""
-
- token: str
- """The token of the stream"""
-
- stream_url: str = FieldInfo(alias="streamUrl")
- """The URL of the stream"""
diff --git a/src/mobilerun/types/task_run_streamed_params.py b/src/mobilerun/types/task_run_streamed_params.py
deleted file mode 100644
index b4975ad..0000000
--- a/src/mobilerun/types/task_run_streamed_params.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Dict, Iterable, Optional
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-from .llm_model import LlmModel
-
-__all__ = ["TaskRunStreamedParams", "Credential"]
-
-
-class TaskRunStreamedParams(TypedDict, total=False):
- llm_model: Required[Annotated[LlmModel, PropertyInfo(alias="llmModel")]]
-
- task: Required[str]
-
- apps: SequenceNotStr[str]
-
- credentials: Iterable[Credential]
-
- device_id: Annotated[Optional[str], PropertyInfo(alias="deviceId")]
- """The ID of the device to run the task on."""
-
- display_id: Annotated[int, PropertyInfo(alias="displayId")]
- """The display ID of the device to run the task on."""
-
- execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")]
-
- files: SequenceNotStr[str]
-
- max_steps: Annotated[int, PropertyInfo(alias="maxSteps")]
-
- output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")]
-
- reasoning: bool
-
- temperature: float
-
- vision: bool
-
- vpn_country: Annotated[
- Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]], PropertyInfo(alias="vpnCountry")
- ]
-
-
-class Credential(TypedDict, total=False):
- credential_names: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="credentialNames")]]
-
- package_name: Required[Annotated[str, PropertyInfo(alias="packageName")]]
diff --git a/tests/api_resources/test_hooks.py b/tests/api_resources/test_hooks.py
index 84267f7..a26899b 100644
--- a/tests/api_resources/test_hooks.py
+++ b/tests/api_resources/test_hooks.py
@@ -10,7 +10,6 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
from mobilerun.types import (
- HookListResponse,
HookUpdateResponse,
HookPerformResponse,
HookRetrieveResponse,
@@ -119,45 +118,6 @@ def test_path_params_update(self, client: Mobilerun) -> None:
hook_id="",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- hook = client.hooks.list()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- hook = client.hooks.list(
- order_by="orderBy",
- order_by_direction="asc",
- page=1,
- page_size=1,
- )
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.hooks.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- hook = response.parse()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.hooks.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- hook = response.parse()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_get_sample_data(self, client: Mobilerun) -> None:
@@ -400,45 +360,6 @@ async def test_path_params_update(self, async_client: AsyncMobilerun) -> None:
hook_id="",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- hook = await async_client.hooks.list()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- hook = await async_client.hooks.list(
- order_by="orderBy",
- order_by_direction="asc",
- page=1,
- page_size=1,
- )
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.hooks.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- hook = await response.parse()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.hooks.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- hook = await response.parse()
- assert_matches_type(HookListResponse, hook, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_get_sample_data(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py
index eede77a..3a0168f 100644
--- a/tests/api_resources/test_tasks.py
+++ b/tests/api_resources/test_tasks.py
@@ -9,14 +9,7 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
-from mobilerun.types import (
- TaskRunResponse,
- TaskListResponse,
- TaskStopResponse,
- TaskRetrieveResponse,
- TaskGetStatusResponse,
- TaskGetTrajectoryResponse,
-)
+from mobilerun.types import TaskStopResponse, TaskRetrieveResponse, TaskGetStatusResponse, TaskGetTrajectoryResponse
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -66,47 +59,6 @@ def test_path_params_retrieve(self, client: Mobilerun) -> None:
"",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list(self, client: Mobilerun) -> None:
- task = client.tasks.list()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_list_with_all_params(self, client: Mobilerun) -> None:
- task = client.tasks.list(
- order_by="id",
- order_by_direction="asc",
- page=1,
- page_size=1,
- query="query",
- status="created",
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.tasks.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.tasks.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_attach(self, client: Mobilerun) -> None:
@@ -233,76 +185,16 @@ def test_path_params_get_trajectory(self, client: Mobilerun) -> None:
"",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_run(self, client: Mobilerun) -> None:
- task = client.tasks.run()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_raw_response_run(self, client: Mobilerun) -> None:
- response = client.tasks.with_raw_response.run()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = response.parse()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_streaming_response_run(self, client: Mobilerun) -> None:
- with client.tasks.with_streaming_response.run() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = response.parse()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_run_streamed(self, client: Mobilerun) -> None:
- task = client.tasks.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- )
- assert task is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None:
- task = client.tasks.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- apps=["string"],
- credentials=[
- {
- "credential_names": ["string"],
- "package_name": "packageName",
- }
- ],
- device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- display_id=0,
- execution_timeout=0,
- files=["string"],
- max_steps=0,
- output_schema={"foo": "bar"},
- reasoning=True,
- temperature=0,
- vision=True,
- vpn_country="US",
- )
+ task = client.tasks.run_streamed()
assert task is None
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_raw_response_run_streamed(self, client: Mobilerun) -> None:
- response = client.tasks.with_raw_response.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- )
+ response = client.tasks.with_raw_response.run_streamed()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -312,10 +204,7 @@ def test_raw_response_run_streamed(self, client: Mobilerun) -> None:
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_streaming_response_run_streamed(self, client: Mobilerun) -> None:
- with client.tasks.with_streaming_response.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- ) as response:
+ with client.tasks.with_streaming_response.run_streamed() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -414,47 +303,6 @@ async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
"",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.list()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.list(
- order_by="id",
- order_by_direction="asc",
- page=1,
- page_size=1,
- query="query",
- status="created",
- )
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.tasks.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = await response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
- async with async_client.tasks.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = await response.parse()
- assert_matches_type(TaskListResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_attach(self, async_client: AsyncMobilerun) -> None:
@@ -581,76 +429,16 @@ async def test_path_params_get_trajectory(self, async_client: AsyncMobilerun) ->
"",
)
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_run(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.run()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.tasks.with_raw_response.run()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- task = await response.parse()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_streaming_response_run(self, async_client: AsyncMobilerun) -> None:
- async with async_client.tasks.with_streaming_response.run() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- task = await response.parse()
- assert_matches_type(TaskRunResponse, task, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_run_streamed(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- )
- assert task is None
-
- @pytest.mark.skip(reason="Prism tests are disabled")
- @parametrize
- async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobilerun) -> None:
- task = await async_client.tasks.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- apps=["string"],
- credentials=[
- {
- "credential_names": ["string"],
- "package_name": "packageName",
- }
- ],
- device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- display_id=0,
- execution_timeout=0,
- files=["string"],
- max_steps=0,
- output_schema={"foo": "bar"},
- reasoning=True,
- temperature=0,
- vision=True,
- vpn_country="US",
- )
+ task = await async_client.tasks.run_streamed()
assert task is None
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_raw_response_run_streamed(self, async_client: AsyncMobilerun) -> None:
- response = await async_client.tasks.with_raw_response.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- )
+ response = await async_client.tasks.with_raw_response.run_streamed()
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -660,10 +448,7 @@ async def test_raw_response_run_streamed(self, async_client: AsyncMobilerun) ->
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_streaming_response_run_streamed(self, async_client: AsyncMobilerun) -> None:
- async with async_client.tasks.with_streaming_response.run_streamed(
- llm_model="openai/gpt-5.1",
- task="x",
- ) as response:
+ async with async_client.tasks.with_streaming_response.run_streamed() as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
diff --git a/tests/test_client.py b/tests/test_client.py
index 8c4f9eb..67064d6 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -860,20 +860,22 @@ def test_parse_retry_after_header(
@mock.patch("mobilerun._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Mobilerun) -> None:
- respx_mock.get("/tasks/").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(
+ side_effect=httpx.TimeoutException("Test timeout error")
+ )
with pytest.raises(APITimeoutError):
- client.tasks.with_streaming_response.list().__enter__()
+ client.tasks.with_streaming_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").__enter__()
assert _get_open_connections(client) == 0
@mock.patch("mobilerun._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Mobilerun) -> None:
- respx_mock.get("/tasks/").mock(return_value=httpx.Response(500))
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- client.tasks.with_streaming_response.list().__enter__()
+ client.tasks.with_streaming_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").__enter__()
assert _get_open_connections(client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@@ -900,9 +902,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.list()
+ response = client.tasks.with_raw_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -924,9 +926,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()})
+ response = client.tasks.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": Omit()}
+ )
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -947,9 +951,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"})
+ response = client.tasks.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": "42"}
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
@@ -1769,10 +1775,14 @@ async def test_parse_retry_after_header(
async def test_retrying_timeout_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncMobilerun
) -> None:
- respx_mock.get("/tasks/").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(
+ side_effect=httpx.TimeoutException("Test timeout error")
+ )
with pytest.raises(APITimeoutError):
- await async_client.tasks.with_streaming_response.list().__aenter__()
+ await async_client.tasks.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"
+ ).__aenter__()
assert _get_open_connections(async_client) == 0
@@ -1781,10 +1791,12 @@ async def test_retrying_timeout_errors_doesnt_leak(
async def test_retrying_status_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncMobilerun
) -> None:
- respx_mock.get("/tasks/").mock(return_value=httpx.Response(500))
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await async_client.tasks.with_streaming_response.list().__aenter__()
+ await async_client.tasks.with_streaming_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"
+ ).__aenter__()
assert _get_open_connections(async_client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@@ -1811,9 +1823,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.list()
+ response = await client.tasks.with_raw_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -1835,9 +1847,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()})
+ response = await client.tasks.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": Omit()}
+ )
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -1858,9 +1872,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"})
+ response = await client.tasks.with_raw_response.retrieve(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": "42"}
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
From fdc6d3cd2d2ecfce66ae84ef34f8111f47fbf609 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 07:12:11 +0000
Subject: [PATCH 22/25] feat(api): api update
---
.stats.yml | 4 ++--
README.md | 12 ++++++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 39d3be5..6737911 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 47
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-825adf3ea9bf2a0f6fca08379e9976d62c50dfc38fa57e6da7710bbf5183a89e.yml
-openapi_spec_hash: a1bf4abae9edb6f6739bce4a1d8c90a4
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-36ef2a444a065b24fda25e8cb3e6612e88b7056d3f34f5b1e8715b63bf52163a.yml
+openapi_spec_hash: c5ccdf970829be56cad60a1f1bd797d6
config_hash: 97b79867ce1dca69c6872bcea77574fb
diff --git a/README.md b/README.md
index 927a65b..b4f6bd3 100644
--- a/README.md
+++ b/README.md
@@ -34,9 +34,12 @@ pip install mobilerun-sdk
The full API of this library can be found in [api.md](api.md).
```python
+import os
from mobilerun import Mobilerun
-client = Mobilerun()
+client = Mobilerun(
+ api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
+)
task = client.tasks.retrieve(
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
@@ -54,10 +57,13 @@ so that your API Key is not stored in source control.
Simply import `AsyncMobilerun` instead of `Mobilerun` and use `await` with each API call:
```python
+import os
import asyncio
from mobilerun import AsyncMobilerun
-client = AsyncMobilerun()
+client = AsyncMobilerun(
+ api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
+)
async def main() -> None:
@@ -86,6 +92,7 @@ pip install mobilerun-sdk[aiohttp]
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
```python
+import os
import asyncio
from mobilerun import DefaultAioHttpClient
from mobilerun import AsyncMobilerun
@@ -93,6 +100,7 @@ from mobilerun import AsyncMobilerun
async def main() -> None:
async with AsyncMobilerun(
+ api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
http_client=DefaultAioHttpClient(),
) as client:
task = await client.tasks.retrieve(
From a27d844d5ca5cecc754a2a3e0eb88712a8540d43 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 07:14:01 +0000
Subject: [PATCH 23/25] feat(api): manual updates
---
.stats.yml | 4 +-
api.md | 7 +
src/mobilerun/resources/devices/apps.py | 100 ++++++++++++
src/mobilerun/resources/hooks.py | 108 ++++++++++++-
src/mobilerun/resources/tasks/tasks.py | 186 +++++++++++++++++++++-
src/mobilerun/types/__init__.py | 5 +
src/mobilerun/types/hook_list_params.py | 20 +++
src/mobilerun/types/hook_list_response.py | 60 +++++++
src/mobilerun/types/task_list_params.py | 28 ++++
src/mobilerun/types/task_list_response.py | 40 +++++
src/mobilerun/types/task_run_response.py | 18 +++
tests/api_resources/devices/test_apps.py | 124 +++++++++++++++
tests/api_resources/test_hooks.py | 79 +++++++++
tests/api_resources/test_tasks.py | 147 ++++++++++++++++-
14 files changed, 921 insertions(+), 5 deletions(-)
create mode 100644 src/mobilerun/types/hook_list_params.py
create mode 100644 src/mobilerun/types/hook_list_response.py
create mode 100644 src/mobilerun/types/task_list_params.py
create mode 100644 src/mobilerun/types/task_list_response.py
create mode 100644 src/mobilerun/types/task_run_response.py
diff --git a/.stats.yml b/.stats.yml
index 6737911..0162610 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 47
+configured_endpoints: 51
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-36ef2a444a065b24fda25e8cb3e6612e88b7056d3f34f5b1e8715b63bf52163a.yml
openapi_spec_hash: c5ccdf970829be56cad60a1f1bd797d6
-config_hash: 97b79867ce1dca69c6872bcea77574fb
+config_hash: 467ca5d67ca7b70ba087d9310f67f344
diff --git a/api.md b/api.md
index e5c341a..1d226a3 100644
--- a/api.md
+++ b/api.md
@@ -8,8 +8,10 @@ from mobilerun.types import (
Task,
TaskStatus,
TaskRetrieveResponse,
+ TaskListResponse,
TaskGetStatusResponse,
TaskGetTrajectoryResponse,
+ TaskRunResponse,
TaskStopResponse,
)
```
@@ -17,9 +19,11 @@ from mobilerun.types import (
Methods:
- client.tasks.retrieve(task_id) -> TaskRetrieveResponse
+- client.tasks.list(\*\*params) -> TaskListResponse
- client.tasks.attach(task_id) -> None
- client.tasks.get_status(task_id) -> TaskGetStatusResponse
- client.tasks.get_trajectory(task_id) -> TaskGetTrajectoryResponse
+- client.tasks.run() -> TaskRunResponse
- client.tasks.run_streamed() -> None
- client.tasks.stop(task_id) -> TaskStopResponse
@@ -98,6 +102,7 @@ from mobilerun.types.devices import AppListResponse
Methods:
+- client.devices.apps.update(package_name, \*, device_id) -> None
- client.devices.apps.list(device_id, \*\*params) -> Optional[AppListResponse]
- client.devices.apps.delete(package_name, \*, device_id) -> None
- client.devices.apps.install(device_id, \*\*params) -> None
@@ -217,6 +222,7 @@ Types:
from mobilerun.types import (
HookRetrieveResponse,
HookUpdateResponse,
+ HookListResponse,
HookGetSampleDataResponse,
HookPerformResponse,
HookSubscribeResponse,
@@ -228,6 +234,7 @@ Methods:
- client.hooks.retrieve(hook_id) -> HookRetrieveResponse
- client.hooks.update(hook_id, \*\*params) -> HookUpdateResponse
+- client.hooks.list(\*\*params) -> HookListResponse
- client.hooks.get_sample_data() -> HookGetSampleDataResponse
- client.hooks.perform() -> HookPerformResponse
- client.hooks.subscribe(\*\*params) -> HookSubscribeResponse
diff --git a/src/mobilerun/resources/devices/apps.py b/src/mobilerun/resources/devices/apps.py
index e0ddd9b..f7f1d36 100644
--- a/src/mobilerun/resources/devices/apps.py
+++ b/src/mobilerun/resources/devices/apps.py
@@ -43,6 +43,50 @@ def with_streaming_response(self) -> AppsResourceWithStreamingResponse:
"""
return AppsResourceWithStreamingResponse(self)
+ def update(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Stop app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._patch(
+ f"/devices/{device_id}/apps/{package_name}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
def list(
self,
device_id: str,
@@ -242,6 +286,50 @@ def with_streaming_response(self) -> AsyncAppsResourceWithStreamingResponse:
"""
return AsyncAppsResourceWithStreamingResponse(self)
+ async def update(
+ self,
+ package_name: str,
+ *,
+ device_id: str,
+ x_device_display_id: int | Omit = omit,
+ # 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,
+ ) -> None:
+ """
+ Stop app
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ if not package_name:
+ raise ValueError(f"Expected a non-empty value for `package_name` but received {package_name!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._patch(
+ f"/devices/{device_id}/apps/{package_name}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
async def list(
self,
device_id: str,
@@ -427,6 +515,9 @@ class AppsResourceWithRawResponse:
def __init__(self, apps: AppsResource) -> None:
self._apps = apps
+ self.update = to_raw_response_wrapper(
+ apps.update,
+ )
self.list = to_raw_response_wrapper(
apps.list,
)
@@ -445,6 +536,9 @@ class AsyncAppsResourceWithRawResponse:
def __init__(self, apps: AsyncAppsResource) -> None:
self._apps = apps
+ self.update = async_to_raw_response_wrapper(
+ apps.update,
+ )
self.list = async_to_raw_response_wrapper(
apps.list,
)
@@ -463,6 +557,9 @@ class AppsResourceWithStreamingResponse:
def __init__(self, apps: AppsResource) -> None:
self._apps = apps
+ self.update = to_streamed_response_wrapper(
+ apps.update,
+ )
self.list = to_streamed_response_wrapper(
apps.list,
)
@@ -481,6 +578,9 @@ class AsyncAppsResourceWithStreamingResponse:
def __init__(self, apps: AsyncAppsResource) -> None:
self._apps = apps
+ self.update = async_to_streamed_response_wrapper(
+ apps.update,
+ )
self.list = async_to_streamed_response_wrapper(
apps.list,
)
diff --git a/src/mobilerun/resources/hooks.py b/src/mobilerun/resources/hooks.py
index 25f5c72..54e3c01 100644
--- a/src/mobilerun/resources/hooks.py
+++ b/src/mobilerun/resources/hooks.py
@@ -3,10 +3,11 @@
from __future__ import annotations
from typing import Optional
+from typing_extensions import Literal
import httpx
-from ..types import hook_update_params, hook_subscribe_params
+from ..types import hook_list_params, hook_update_params, hook_subscribe_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import maybe_transform, async_maybe_transform
from .._compat import cached_property
@@ -18,6 +19,7 @@
async_to_streamed_response_wrapper,
)
from .._base_client import make_request_options
+from ..types.hook_list_response import HookListResponse
from ..types.hook_update_response import HookUpdateResponse
from ..types.hook_perform_response import HookPerformResponse
from ..types.hook_retrieve_response import HookRetrieveResponse
@@ -129,6 +131,52 @@ def update(
cast_to=HookUpdateResponse,
)
+ def list(
+ self,
+ *,
+ order_by: Optional[str] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ # 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,
+ ) -> HookListResponse:
+ """
+ List hooks belonging to the requesting user (paginated).
+
+ 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
+ """
+ return self._get(
+ "/hooks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ },
+ hook_list_params.HookListParams,
+ ),
+ ),
+ cast_to=HookListResponse,
+ )
+
def get_sample_data(
self,
*,
@@ -353,6 +401,52 @@ async def update(
cast_to=HookUpdateResponse,
)
+ async def list(
+ self,
+ *,
+ order_by: Optional[str] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: int | Omit = omit,
+ page_size: int | Omit = omit,
+ # 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,
+ ) -> HookListResponse:
+ """
+ List hooks belonging to the requesting user (paginated).
+
+ 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
+ """
+ return await self._get(
+ "/hooks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ },
+ hook_list_params.HookListParams,
+ ),
+ ),
+ cast_to=HookListResponse,
+ )
+
async def get_sample_data(
self,
*,
@@ -486,6 +580,9 @@ def __init__(self, hooks: HooksResource) -> None:
self.update = to_raw_response_wrapper(
hooks.update,
)
+ self.list = to_raw_response_wrapper(
+ hooks.list,
+ )
self.get_sample_data = to_raw_response_wrapper(
hooks.get_sample_data,
)
@@ -510,6 +607,9 @@ def __init__(self, hooks: AsyncHooksResource) -> None:
self.update = async_to_raw_response_wrapper(
hooks.update,
)
+ self.list = async_to_raw_response_wrapper(
+ hooks.list,
+ )
self.get_sample_data = async_to_raw_response_wrapper(
hooks.get_sample_data,
)
@@ -534,6 +634,9 @@ def __init__(self, hooks: HooksResource) -> None:
self.update = to_streamed_response_wrapper(
hooks.update,
)
+ self.list = to_streamed_response_wrapper(
+ hooks.list,
+ )
self.get_sample_data = to_streamed_response_wrapper(
hooks.get_sample_data,
)
@@ -558,6 +661,9 @@ def __init__(self, hooks: AsyncHooksResource) -> None:
self.update = async_to_streamed_response_wrapper(
hooks.update,
)
+ self.list = async_to_streamed_response_wrapper(
+ hooks.list,
+ )
self.get_sample_data = async_to_streamed_response_wrapper(
hooks.get_sample_data,
)
diff --git a/src/mobilerun/resources/tasks/tasks.py b/src/mobilerun/resources/tasks/tasks.py
index c584e49..f409f2c 100644
--- a/src/mobilerun/resources/tasks/tasks.py
+++ b/src/mobilerun/resources/tasks/tasks.py
@@ -2,9 +2,14 @@
from __future__ import annotations
+from typing import Optional
+from typing_extensions import Literal
+
import httpx
-from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given
+from ...types import TaskStatus, task_list_params
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
from ..._compat import cached_property
from .ui_states import (
UiStatesResource,
@@ -30,6 +35,9 @@
AsyncScreenshotsResourceWithStreamingResponse,
)
from ..._base_client import make_request_options
+from ...types.task_status import TaskStatus
+from ...types.task_run_response import TaskRunResponse
+from ...types.task_list_response import TaskListResponse
from ...types.task_stop_response import TaskStopResponse
from ...types.task_retrieve_response import TaskRetrieveResponse
from ...types.task_get_status_response import TaskGetStatusResponse
@@ -99,6 +107,63 @@ def retrieve(
cast_to=TaskRetrieveResponse,
)
+ def list(
+ self,
+ *,
+ order_by: Optional[Literal["id", "createdAt", "finishedAt", "status"]] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: Optional[int] | Omit = omit,
+ page_size: int | Omit = omit,
+ query: Optional[str] | Omit = omit,
+ status: Optional[TaskStatus] | Omit = omit,
+ # 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,
+ ) -> TaskListResponse:
+ """List all tasks you've created so far
+
+ Args:
+ page: Page number (1-based).
+
+ If provided, returns paginated results.
+
+ page_size: Number of items per page
+
+ query: Search in task description.
+
+ 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
+ """
+ return self._get(
+ "/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ "query": query,
+ "status": status,
+ },
+ task_list_params.TaskListParams,
+ ),
+ ),
+ cast_to=TaskListResponse,
+ )
+
def attach(
self,
task_id: str,
@@ -199,6 +264,25 @@ def get_trajectory(
cast_to=TaskGetTrajectoryResponse,
)
+ def run(
+ self,
+ *,
+ # 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,
+ ) -> TaskRunResponse:
+ """Run Task"""
+ return self._post(
+ "/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskRunResponse,
+ )
+
def run_streamed(
self,
*,
@@ -314,6 +398,63 @@ async def retrieve(
cast_to=TaskRetrieveResponse,
)
+ async def list(
+ self,
+ *,
+ order_by: Optional[Literal["id", "createdAt", "finishedAt", "status"]] | Omit = omit,
+ order_by_direction: Literal["asc", "desc"] | Omit = omit,
+ page: Optional[int] | Omit = omit,
+ page_size: int | Omit = omit,
+ query: Optional[str] | Omit = omit,
+ status: Optional[TaskStatus] | Omit = omit,
+ # 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,
+ ) -> TaskListResponse:
+ """List all tasks you've created so far
+
+ Args:
+ page: Page number (1-based).
+
+ If provided, returns paginated results.
+
+ page_size: Number of items per page
+
+ query: Search in task description.
+
+ 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
+ """
+ return await self._get(
+ "/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "order_by": order_by,
+ "order_by_direction": order_by_direction,
+ "page": page,
+ "page_size": page_size,
+ "query": query,
+ "status": status,
+ },
+ task_list_params.TaskListParams,
+ ),
+ ),
+ cast_to=TaskListResponse,
+ )
+
async def attach(
self,
task_id: str,
@@ -414,6 +555,25 @@ async def get_trajectory(
cast_to=TaskGetTrajectoryResponse,
)
+ async def run(
+ self,
+ *,
+ # 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,
+ ) -> TaskRunResponse:
+ """Run Task"""
+ return await self._post(
+ "/tasks",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=TaskRunResponse,
+ )
+
async def run_streamed(
self,
*,
@@ -475,6 +635,9 @@ def __init__(self, tasks: TasksResource) -> None:
self.retrieve = to_raw_response_wrapper(
tasks.retrieve,
)
+ self.list = to_raw_response_wrapper(
+ tasks.list,
+ )
self.attach = to_raw_response_wrapper(
tasks.attach,
)
@@ -484,6 +647,9 @@ def __init__(self, tasks: TasksResource) -> None:
self.get_trajectory = to_raw_response_wrapper(
tasks.get_trajectory,
)
+ self.run = to_raw_response_wrapper(
+ tasks.run,
+ )
self.run_streamed = to_raw_response_wrapper(
tasks.run_streamed,
)
@@ -507,6 +673,9 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.retrieve = async_to_raw_response_wrapper(
tasks.retrieve,
)
+ self.list = async_to_raw_response_wrapper(
+ tasks.list,
+ )
self.attach = async_to_raw_response_wrapper(
tasks.attach,
)
@@ -516,6 +685,9 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.get_trajectory = async_to_raw_response_wrapper(
tasks.get_trajectory,
)
+ self.run = async_to_raw_response_wrapper(
+ tasks.run,
+ )
self.run_streamed = async_to_raw_response_wrapper(
tasks.run_streamed,
)
@@ -539,6 +711,9 @@ def __init__(self, tasks: TasksResource) -> None:
self.retrieve = to_streamed_response_wrapper(
tasks.retrieve,
)
+ self.list = to_streamed_response_wrapper(
+ tasks.list,
+ )
self.attach = to_streamed_response_wrapper(
tasks.attach,
)
@@ -548,6 +723,9 @@ def __init__(self, tasks: TasksResource) -> None:
self.get_trajectory = to_streamed_response_wrapper(
tasks.get_trajectory,
)
+ self.run = to_streamed_response_wrapper(
+ tasks.run,
+ )
self.run_streamed = to_streamed_response_wrapper(
tasks.run_streamed,
)
@@ -571,6 +749,9 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.retrieve = async_to_streamed_response_wrapper(
tasks.retrieve,
)
+ self.list = async_to_streamed_response_wrapper(
+ tasks.list,
+ )
self.attach = async_to_streamed_response_wrapper(
tasks.attach,
)
@@ -580,6 +761,9 @@ def __init__(self, tasks: AsyncTasksResource) -> None:
self.get_trajectory = async_to_streamed_response_wrapper(
tasks.get_trajectory,
)
+ self.run = async_to_streamed_response_wrapper(
+ tasks.run,
+ )
self.run_streamed = async_to_streamed_response_wrapper(
tasks.run_streamed,
)
diff --git a/src/mobilerun/types/__init__.py b/src/mobilerun/types/__init__.py
index c7e41e4..42ca86d 100644
--- a/src/mobilerun/types/__init__.py
+++ b/src/mobilerun/types/__init__.py
@@ -7,9 +7,14 @@
from .llm_model import LlmModel as LlmModel
from .task_status import TaskStatus as TaskStatus
from .app_list_params import AppListParams as AppListParams
+from .hook_list_params import HookListParams as HookListParams
+from .task_list_params import TaskListParams as TaskListParams
from .app_list_response import AppListResponse as AppListResponse
+from .task_run_response import TaskRunResponse as TaskRunResponse
from .device_list_params import DeviceListParams as DeviceListParams
+from .hook_list_response import HookListResponse as HookListResponse
from .hook_update_params import HookUpdateParams as HookUpdateParams
+from .task_list_response import TaskListResponse as TaskListResponse
from .task_stop_response import TaskStopResponse as TaskStopResponse
from .device_create_params import DeviceCreateParams as DeviceCreateParams
from .device_list_response import DeviceListResponse as DeviceListResponse
diff --git a/src/mobilerun/types/hook_list_params.py b/src/mobilerun/types/hook_list_params.py
new file mode 100644
index 0000000..5d3fe14
--- /dev/null
+++ b/src/mobilerun/types/hook_list_params.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["HookListParams"]
+
+
+class HookListParams(TypedDict, total=False):
+ order_by: Annotated[Optional[str], PropertyInfo(alias="orderBy")]
+
+ order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
+
+ page: int
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
diff --git a/src/mobilerun/types/hook_list_response.py b/src/mobilerun/types/hook_list_response.py
new file mode 100644
index 0000000..dbc468c
--- /dev/null
+++ b/src/mobilerun/types/hook_list_response.py
@@ -0,0 +1,60 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+from .task_status import TaskStatus
+
+__all__ = ["HookListResponse", "Item", "Pagination"]
+
+
+class Item(BaseModel):
+ service: Literal["zapier", "n8n", "make", "internal", "other"]
+
+ url: str
+
+ user_id: str = FieldInfo(alias="userId")
+
+ id: Optional[str] = None
+
+ created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
+
+ events: Optional[List[TaskStatus]] = None
+
+ state: Optional[Literal["active", "disabled", "deleted"]] = None
+
+ updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
+
+
+class Pagination(BaseModel):
+ """Pagination metadata"""
+
+ has_next: bool = FieldInfo(alias="hasNext")
+ """Whether there is a next page"""
+
+ has_prev: bool = FieldInfo(alias="hasPrev")
+ """Whether there is a previous page"""
+
+ page: int
+ """Current page number (1-based)"""
+
+ pages: int
+ """Total number of pages"""
+
+ page_size: int = FieldInfo(alias="pageSize")
+ """Number of items per page"""
+
+ total: int
+ """Total number of items"""
+
+
+class HookListResponse(BaseModel):
+ items: List[Item]
+ """The paginated items"""
+
+ pagination: Pagination
+ """Pagination metadata"""
diff --git a/src/mobilerun/types/task_list_params.py b/src/mobilerun/types/task_list_params.py
new file mode 100644
index 0000000..08881ad
--- /dev/null
+++ b/src/mobilerun/types/task_list_params.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+from .task_status import TaskStatus
+
+__all__ = ["TaskListParams"]
+
+
+class TaskListParams(TypedDict, total=False):
+ order_by: Annotated[Optional[Literal["id", "createdAt", "finishedAt", "status"]], PropertyInfo(alias="orderBy")]
+
+ order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")]
+
+ page: Optional[int]
+ """Page number (1-based). If provided, returns paginated results."""
+
+ page_size: Annotated[int, PropertyInfo(alias="pageSize")]
+ """Number of items per page"""
+
+ query: Optional[str]
+ """Search in task description."""
+
+ status: Optional[TaskStatus]
diff --git a/src/mobilerun/types/task_list_response.py b/src/mobilerun/types/task_list_response.py
new file mode 100644
index 0000000..0860788
--- /dev/null
+++ b/src/mobilerun/types/task_list_response.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from pydantic import Field as FieldInfo
+
+from .task import Task
+from .._models import BaseModel
+
+__all__ = ["TaskListResponse", "Pagination"]
+
+
+class Pagination(BaseModel):
+ """Pagination metadata"""
+
+ has_next: bool = FieldInfo(alias="hasNext")
+ """Whether there is a next page"""
+
+ has_prev: bool = FieldInfo(alias="hasPrev")
+ """Whether there is a previous page"""
+
+ page: int
+ """Current page number (1-based)"""
+
+ pages: int
+ """Total number of pages"""
+
+ page_size: int = FieldInfo(alias="pageSize")
+ """Number of items per page"""
+
+ total: int
+ """Total number of items"""
+
+
+class TaskListResponse(BaseModel):
+ items: List[Task]
+ """The paginated items"""
+
+ pagination: Pagination
+ """Pagination metadata"""
diff --git a/src/mobilerun/types/task_run_response.py b/src/mobilerun/types/task_run_response.py
new file mode 100644
index 0000000..4e61f59
--- /dev/null
+++ b/src/mobilerun/types/task_run_response.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["TaskRunResponse"]
+
+
+class TaskRunResponse(BaseModel):
+ id: str
+ """The ID of the task"""
+
+ token: str
+ """The token of the stream"""
+
+ stream_url: str = FieldInfo(alias="streamUrl")
+ """The URL of the stream"""
diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py
index 6469d82..a54f742 100644
--- a/tests/api_resources/devices/test_apps.py
+++ b/tests/api_resources/devices/test_apps.py
@@ -17,6 +17,68 @@
class TestApps:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Mobilerun) -> None:
+ app = client.devices.apps.update(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
+ app = client.devices.apps.update(
+ package_name="packageName",
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Mobilerun) -> None:
+ response = client.devices.apps.with_raw_response.update(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Mobilerun) -> None:
+ with client.devices.apps.with_streaming_response.update(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_path_params_update(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.apps.with_raw_response.update(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ client.devices.apps.with_raw_response.update(
+ package_name="",
+ device_id="deviceId",
+ )
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_list(self, client: Mobilerun) -> None:
@@ -256,6 +318,68 @@ class TestAsyncApps:
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.update(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ app = await async_client.devices.apps.update(
+ package_name="packageName",
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.apps.with_raw_response.update(
+ package_name="packageName",
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert app is None
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.apps.with_streaming_response.update(
+ package_name="packageName",
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert app is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.apps.with_raw_response.update(
+ package_name="packageName",
+ device_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"):
+ await async_client.devices.apps.with_raw_response.update(
+ package_name="",
+ device_id="deviceId",
+ )
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_list(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/test_hooks.py b/tests/api_resources/test_hooks.py
index a26899b..84267f7 100644
--- a/tests/api_resources/test_hooks.py
+++ b/tests/api_resources/test_hooks.py
@@ -10,6 +10,7 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
from mobilerun.types import (
+ HookListResponse,
HookUpdateResponse,
HookPerformResponse,
HookRetrieveResponse,
@@ -118,6 +119,45 @@ def test_path_params_update(self, client: Mobilerun) -> None:
hook_id="",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ hook = client.hooks.list()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ hook = client.hooks.list(
+ order_by="orderBy",
+ order_by_direction="asc",
+ page=1,
+ page_size=1,
+ )
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.hooks.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ hook = response.parse()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.hooks.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ hook = response.parse()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_get_sample_data(self, client: Mobilerun) -> None:
@@ -360,6 +400,45 @@ async def test_path_params_update(self, async_client: AsyncMobilerun) -> None:
hook_id="",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ hook = await async_client.hooks.list()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ hook = await async_client.hooks.list(
+ order_by="orderBy",
+ order_by_direction="asc",
+ page=1,
+ page_size=1,
+ )
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.hooks.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ hook = await response.parse()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.hooks.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ hook = await response.parse()
+ assert_matches_type(HookListResponse, hook, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_get_sample_data(self, async_client: AsyncMobilerun) -> None:
diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py
index 3a0168f..93873ee 100644
--- a/tests/api_resources/test_tasks.py
+++ b/tests/api_resources/test_tasks.py
@@ -9,7 +9,14 @@
from mobilerun import Mobilerun, AsyncMobilerun
from tests.utils import assert_matches_type
-from mobilerun.types import TaskStopResponse, TaskRetrieveResponse, TaskGetStatusResponse, TaskGetTrajectoryResponse
+from mobilerun.types import (
+ TaskRunResponse,
+ TaskListResponse,
+ TaskStopResponse,
+ TaskRetrieveResponse,
+ TaskGetStatusResponse,
+ TaskGetTrajectoryResponse,
+)
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -59,6 +66,47 @@ def test_path_params_retrieve(self, client: Mobilerun) -> None:
"",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ task = client.tasks.list()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ task = client.tasks.list(
+ order_by="id",
+ order_by_direction="asc",
+ page=1,
+ page_size=1,
+ query="query",
+ status="created",
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.tasks.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.tasks.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_attach(self, client: Mobilerun) -> None:
@@ -185,6 +233,34 @@ def test_path_params_get_trajectory(self, client: Mobilerun) -> None:
"",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_method_run(self, client: Mobilerun) -> None:
+ task = client.tasks.run()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_raw_response_run(self, client: Mobilerun) -> None:
+ response = client.tasks.with_raw_response.run()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = response.parse()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ def test_streaming_response_run(self, client: Mobilerun) -> None:
+ with client.tasks.with_streaming_response.run() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = response.parse()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
def test_method_run_streamed(self, client: Mobilerun) -> None:
@@ -303,6 +379,47 @@ async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
"",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ task = await async_client.tasks.list()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ task = await async_client.tasks.list(
+ order_by="id",
+ order_by_direction="asc",
+ page=1,
+ page_size=1,
+ query="query",
+ status="created",
+ )
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.tasks.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = await response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.tasks.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = await response.parse()
+ assert_matches_type(TaskListResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_attach(self, async_client: AsyncMobilerun) -> None:
@@ -429,6 +546,34 @@ async def test_path_params_get_trajectory(self, async_client: AsyncMobilerun) ->
"",
)
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_method_run(self, async_client: AsyncMobilerun) -> None:
+ task = await async_client.tasks.run()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_raw_response_run(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.tasks.with_raw_response.run()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ task = await response.parse()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ @pytest.mark.skip(reason="Prism tests are disabled")
+ @parametrize
+ async def test_streaming_response_run(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.tasks.with_streaming_response.run() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ task = await response.parse()
+ assert_matches_type(TaskRunResponse, task, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
@pytest.mark.skip(reason="Prism tests are disabled")
@parametrize
async def test_method_run_streamed(self, async_client: AsyncMobilerun) -> None:
From e529cf666a09be899a1af449735a2759b307762b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 07:14:53 +0000
Subject: [PATCH 24/25] feat(api): manual updates
---
.stats.yml | 2 +-
README.md | 42 ++++++++++-----------------------
tests/test_client.py | 56 ++++++++++++++++----------------------------
3 files changed, 34 insertions(+), 66 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 0162610..21aafc2 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 51
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun%2Fdroidrun-cloud-36ef2a444a065b24fda25e8cb3e6612e88b7056d3f34f5b1e8715b63bf52163a.yml
openapi_spec_hash: c5ccdf970829be56cad60a1f1bd797d6
-config_hash: 467ca5d67ca7b70ba087d9310f67f344
+config_hash: 301a5a6069197d416d0877c4d3fc0fb0
diff --git a/README.md b/README.md
index b4f6bd3..fd577f2 100644
--- a/README.md
+++ b/README.md
@@ -41,10 +41,8 @@ client = Mobilerun(
api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
)
-task = client.tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
-)
-print(task.task)
+tasks = client.tasks.list()
+print(tasks.items)
```
While you can provide a `api_key` keyword argument,
@@ -67,10 +65,8 @@ client = AsyncMobilerun(
async def main() -> None:
- task = await client.tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
- print(task.task)
+ tasks = await client.tasks.list()
+ print(tasks.items)
asyncio.run(main())
@@ -103,10 +99,8 @@ async def main() -> None:
api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted
http_client=DefaultAioHttpClient(),
) as client:
- task = await client.tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
- print(task.task)
+ tasks = await client.tasks.list()
+ print(tasks.items)
asyncio.run(main())
@@ -157,9 +151,7 @@ from mobilerun import Mobilerun
client = Mobilerun()
try:
- client.tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
- )
+ client.tasks.list()
except mobilerun.APIConnectionError as e:
print("The server could not be reached")
print(e.__cause__) # an underlying Exception, likely raised within httpx.
@@ -202,9 +194,7 @@ client = Mobilerun(
)
# Or, configure per-request:
-client.with_options(max_retries=5).tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
-)
+client.with_options(max_retries=5).tasks.list()
```
### Timeouts
@@ -227,9 +217,7 @@ client = Mobilerun(
)
# Override per-request:
-client.with_options(timeout=5.0).tasks.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
-)
+client.with_options(timeout=5.0).tasks.list()
```
On timeout, an `APITimeoutError` is thrown.
@@ -270,13 +258,11 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to
from mobilerun import Mobilerun
client = Mobilerun()
-response = client.tasks.with_raw_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
-)
+response = client.tasks.with_raw_response.list()
print(response.headers.get('X-My-Header'))
-task = response.parse() # get the object that `tasks.retrieve()` would have returned
-print(task.task)
+task = response.parse() # get the object that `tasks.list()` would have returned
+print(task.items)
```
These methods return an [`APIResponse`](https://github.com/droidrun/mobilerun-sdk-python/tree/main/src/mobilerun/_response.py) object.
@@ -290,9 +276,7 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.tasks.with_streaming_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
-) as response:
+with client.tasks.with_streaming_response.list() as response:
print(response.headers.get("X-My-Header"))
for line in response.iter_lines():
diff --git a/tests/test_client.py b/tests/test_client.py
index 67064d6..ac2d336 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -860,22 +860,20 @@ def test_parse_retry_after_header(
@mock.patch("mobilerun._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Mobilerun) -> None:
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(
- side_effect=httpx.TimeoutException("Test timeout error")
- )
+ respx_mock.get("/tasks").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- client.tasks.with_streaming_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").__enter__()
+ client.tasks.with_streaming_response.list().__enter__()
assert _get_open_connections(client) == 0
@mock.patch("mobilerun._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Mobilerun) -> None:
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(return_value=httpx.Response(500))
+ respx_mock.get("/tasks").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- client.tasks.with_streaming_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").__enter__()
+ client.tasks.with_streaming_response.list().__enter__()
assert _get_open_connections(client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@@ -902,9 +900,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
+ response = client.tasks.with_raw_response.list()
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -926,11 +924,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": Omit()}
- )
+ response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()})
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -951,11 +947,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = client.tasks.with_raw_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": "42"}
- )
+ response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"})
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
@@ -1775,14 +1769,10 @@ async def test_parse_retry_after_header(
async def test_retrying_timeout_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncMobilerun
) -> None:
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(
- side_effect=httpx.TimeoutException("Test timeout error")
- )
+ respx_mock.get("/tasks").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- await async_client.tasks.with_streaming_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"
- ).__aenter__()
+ await async_client.tasks.with_streaming_response.list().__aenter__()
assert _get_open_connections(async_client) == 0
@@ -1791,12 +1781,10 @@ async def test_retrying_timeout_errors_doesnt_leak(
async def test_retrying_status_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncMobilerun
) -> None:
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(return_value=httpx.Response(500))
+ respx_mock.get("/tasks").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await async_client.tasks.with_streaming_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"
- ).__aenter__()
+ await async_client.tasks.with_streaming_response.list().__aenter__()
assert _get_open_connections(async_client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@@ -1823,9 +1811,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.retrieve("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
+ response = await client.tasks.with_raw_response.list()
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@@ -1847,11 +1835,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": Omit()}
- )
+ response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()})
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@@ -1872,11 +1858,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/tasks/182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").mock(side_effect=retry_handler)
+ respx_mock.get("/tasks").mock(side_effect=retry_handler)
- response = await client.tasks.with_raw_response.retrieve(
- "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", extra_headers={"x-stainless-retry-count": "42"}
- )
+ response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"})
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
From 99abd138825cc4cb410e224343e022ccfd8fd9e5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 07:15:09 +0000
Subject: [PATCH 25/25] release: 2.1.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/mobilerun/_version.py | 2 +-
4 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 65f558e..656a2ef 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.0.0"
+ ".": "2.1.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ffa3740..9f727a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Changelog
+## 2.1.0 (2026-02-17)
+
+Full Changelog: [v2.0.0...v2.1.0](https://github.com/droidrun/mobilerun-sdk-python/compare/v2.0.0...v2.1.0)
+
+### Features
+
+* **api:** api update ([fdc6d3c](https://github.com/droidrun/mobilerun-sdk-python/commit/fdc6d3cd2d2ecfce66ae84ef34f8111f47fbf609))
+* **api:** api update ([543bbd8](https://github.com/droidrun/mobilerun-sdk-python/commit/543bbd877819b2dc23ecfe5b3d4722996b54e92b))
+* **api:** api update ([9049554](https://github.com/droidrun/mobilerun-sdk-python/commit/9049554b1ab39ca164a3351861ec41c9ea78d489))
+* **api:** api update ([4c2d97d](https://github.com/droidrun/mobilerun-sdk-python/commit/4c2d97de0a1ae482871912fe677ed64e0919825e))
+* **api:** api update ([8d53e63](https://github.com/droidrun/mobilerun-sdk-python/commit/8d53e63fd8ccebbe5a77af740cd5e6bdf85c2a85))
+* **api:** api update ([678264c](https://github.com/droidrun/mobilerun-sdk-python/commit/678264c95364ad4fff7c70b61bd4794819f28292))
+* **api:** api update ([e42aa53](https://github.com/droidrun/mobilerun-sdk-python/commit/e42aa5309759f931ceab3eee40792e559f21d3a3))
+* **api:** api update ([866c20e](https://github.com/droidrun/mobilerun-sdk-python/commit/866c20ec6ebd177c861777fee900259186347ef0))
+* **api:** api update ([416142e](https://github.com/droidrun/mobilerun-sdk-python/commit/416142eb345a07aefea8404a97231ed0acd74678))
+* **api:** expose device count endpoint ([ab1191d](https://github.com/droidrun/mobilerun-sdk-python/commit/ab1191d28943441844e81c6c1189aebc34f54980))
+* **api:** manual updates ([e529cf6](https://github.com/droidrun/mobilerun-sdk-python/commit/e529cf666a09be899a1af449735a2759b307762b))
+* **api:** manual updates ([a27d844](https://github.com/droidrun/mobilerun-sdk-python/commit/a27d844d5ca5cecc754a2a3e0eb88712a8540d43))
+* **client:** add custom JSON encoder for extended type support ([9471952](https://github.com/droidrun/mobilerun-sdk-python/commit/947195285cae03d555b21716015384cc2e1f3fa0))
+* **client:** add support for binary request streaming ([c6668af](https://github.com/droidrun/mobilerun-sdk-python/commit/c6668af5dbd83d7ab1dd1fe4f68253422e055e73))
+
+
+### Bug Fixes
+
+* **docs:** fix mcp installation instructions for remote servers ([a06f4b2](https://github.com/droidrun/mobilerun-sdk-python/commit/a06f4b2146dafd2c9435fecb603a6217b085fcc5))
+
+
+### Chores
+
+* **ci:** upgrade `actions/github-script` ([00033ad](https://github.com/droidrun/mobilerun-sdk-python/commit/00033ad7ffac1d3d650a05e841bbdecca964192e))
+* format all `api.md` files ([2910e43](https://github.com/droidrun/mobilerun-sdk-python/commit/2910e4312fa6360f754de4d6937d677cd04acc68))
+* **internal:** bump dependencies ([91ab063](https://github.com/droidrun/mobilerun-sdk-python/commit/91ab0631121c4ca096133953344ea83e96cc32ae))
+* **internal:** fix lint error on Python 3.14 ([f5920bc](https://github.com/droidrun/mobilerun-sdk-python/commit/f5920bc46fb52360860c02ca941926e939f3e316))
+* **internal:** update `actions/checkout` version ([75af377](https://github.com/droidrun/mobilerun-sdk-python/commit/75af377b29fca57b52843186af3e9775bfc78c13))
+
## 2.0.0 (2026-01-12)
Full Changelog: [v0.1.0...v2.0.0](https://github.com/droidrun/mobilerun-sdk-python/compare/v0.1.0...v2.0.0)
diff --git a/pyproject.toml b/pyproject.toml
index 3984f67..7719b58 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "mobilerun-sdk"
-version = "2.0.0"
+version = "2.1.0"
description = "The official Python library for the mobilerun API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/mobilerun/_version.py b/src/mobilerun/_version.py
index ed7458a..f24f62b 100644
--- a/src/mobilerun/_version.py
+++ b/src/mobilerun/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "mobilerun"
-__version__ = "2.0.0" # x-release-please-version
+__version__ = "2.1.0" # x-release-please-version