From 55c09f2f6fd3263c3042427b45ec85eed0680b74 Mon Sep 17 00:00:00 2001 From: lutz-grex Date: Thu, 20 Aug 2026 10:25:43 +0200 Subject: [PATCH 1/5] ci: self-hosted release-please on next MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hosted-Stainless release step with community googleapis/release-please-action@v4, running on push to `next` (the branch generation lands on). Requires a RELEASE_PLEASE_TOKEN PAT secret (Contents:RW + PRs:RW) — the default GITHUB_TOKEN cannot trigger publish-pypi.yml's release:published event. Also widen release-doctor's PR trigger to include `next` since release PRs now target it instead of `main`. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WLJNWZ5H1JM4ffk32S8bg3 --- .github/workflows/release-doctor.yml | 1 + .github/workflows/release.yml | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index ba615623..37261b04 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - main + - next workflow_dispatch: jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..f4e6abbb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,20 @@ +name: release-please +on: + push: + branches: + - next + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + target-branch: next + config-file: release-please-config.json + manifest-file: .release-please-manifest.json From 332dcb7a384078489bae09fb7005a15b72b86246 Mon Sep 17 00:00:00 2001 From: lutz-grex Date: Thu, 20 Aug 2026 11:16:53 +0200 Subject: [PATCH 2/5] fix(ci): serialize release-please, ff main, drop prerelease MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds concurrency (group: release-please-next, no cancel-in-progress) so overlapping pushes to next from the generator's regen+stamp commits can't race release-please into a stale-version state. After a release is actually created, fast-forwards main to the released next commit using RELEASE_PLEASE_TOKEN (never a force-push: a non-fast-forward push is rejected, not overwritten). Also drops "versioning": "prerelease" / "prerelease": true from release-please-config.json — that combination only made sense for the old Stainless-fork pipeline. Confirmed from release-please source (versioning-strategies/default.ts and prerelease.ts) that both strategies check the same Release-As commit note identically before computing any bump, so removing them preserves Release-As overrides and yields clean major.minor.patch bumps for normal commits. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01WLJNWZ5H1JM4ffk32S8bg3 --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++ release-please-config.json | 2 -- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f4e6abbb..1a8a0e90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,10 @@ on: branches: - next +concurrency: + group: release-please-next + cancel-in-progress: false + permissions: contents: write pull-requests: write @@ -12,9 +16,35 @@ jobs: release-please: runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + - uses: googleapis/release-please-action@v4 + id: release with: token: ${{ secrets.RELEASE_PLEASE_TOKEN }} target-branch: next config-file: release-please-config.json manifest-file: .release-please-manifest.json + + # release-please tags/releases the existing `next` commit in place; it + # does not itself update `main`. Once a release actually landed, fast + # forward `main` to that commit so `main` always reflects the latest + # released state. This never force-pushes: `git push :main` + # without `-f` is rejected by git/GitHub if it isn't a fast-forward, + # so a divergent `main` fails loudly instead of being overwritten. + - name: Fast-forward main to the released next commit + if: steps.release.outputs.releases_created == 'true' + env: + GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} + run: | + set -euo pipefail + git fetch origin next main + if ! git merge-base --is-ancestor origin/main origin/next; then + echo "::error::origin/main is not an ancestor of origin/next — refusing to fast-forward" >&2 + exit 1 + fi + git push "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" origin/next:main diff --git a/release-please-config.json b/release-please-config.json index 7b4115ed..cae97fd1 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -5,8 +5,6 @@ "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", "include-v-in-tag": true, "include-component-in-tag": false, - "versioning": "prerelease", - "prerelease": true, "bump-minor-pre-major": true, "bump-patch-for-minor-pre-major": false, "pull-request-header": "Automated Release PR", From 8bd21c08cd24053976d4fe7e3b15717b3f30379a Mon Sep 17 00:00:00 2001 From: stlc-bot Date: Thu, 20 Aug 2026 09:42:38 +0000 Subject: [PATCH 3/5] feat(bootstrap): repo-driven STLC pipeline Stainless-Generated-From: 1c035337aa61d321a328a803a87c9f2dcebda90e --- .stats.yml | 5 +- README.md | 41 +- SECURITY.md | 2 +- api.md | 360 ++++- pyproject.toml | 2 +- release-please-config.json | 2 +- scripts/utils/upload-artifact.sh | 2 +- src/mobilerun_sdk/_client.py | 266 ++++ src/mobilerun_sdk/resources/__init__.py | 98 ++ src/mobilerun_sdk/resources/agents.py | 135 ++ .../resources/app_events/__init__.py | 33 + .../resources/app_events/app_events.py | 325 +++++ .../resources/app_events/catalog.py | 227 +++ src/mobilerun_sdk/resources/apps.py | 57 + .../credentials/packages/packages.py | 59 + .../resources/devices/__init__.py | 70 + src/mobilerun_sdk/resources/devices/apps.py | 351 ++++- .../resources/devices/browser.py | 199 +++ .../resources/devices/deep_link.py | 232 ++++ .../resources/devices/devices.py | 472 ++++++- .../resources/devices/esim/__init__.py | 33 + .../resources/devices/esim/apn.py | 437 ++++++ .../resources/devices/{ => esim}/esim.py | 243 +++- src/mobilerun_sdk/resources/devices/kiosk.py | 286 ++++ .../resources/devices/location.py | 96 ++ .../resources/devices/media_sessions.py | 469 +++++++ .../resources/devices/recordings.py | 744 ++++++++++ src/mobilerun_sdk/resources/esims/__init__.py | 33 + src/mobilerun_sdk/resources/esims/esims.py | 1217 +++++++++++++++++ src/mobilerun_sdk/resources/esims/messages.py | 352 +++++ .../resources/messages/__init__.py | 33 + .../resources/messages/conversations.py | 331 +++++ .../resources/messages/messages.py | 255 ++++ src/mobilerun_sdk/resources/notifications.py | 293 ++++ .../resources/numbers/__init__.py | 33 + .../resources/numbers/messages.py | 205 +++ .../resources/numbers/numbers.py | 644 +++++++++ src/mobilerun_sdk/resources/store/__init__.py | 33 + src/mobilerun_sdk/resources/store/apps.py | 355 +++++ src/mobilerun_sdk/resources/store/store.py | 167 +++ .../resources/tasks/screenshots.py | 10 +- src/mobilerun_sdk/resources/tasks/tasks.py | 18 +- .../resources/tasks/ui_states.py | 10 +- .../resources/workflows/executions.py | 81 ++ .../resources/workflows/flows/actions.py | 10 +- .../resources/workflows/flows/flows.py | 198 ++- .../resources/workflows/triggers.py | 16 +- src/mobilerun_sdk/types/__init__.py | 58 +- .../types/agent_list_response.py | 33 + .../types/app_event_list_params.py | 26 + .../types/app_event_list_response.py | 42 + .../types/app_event_retrieve_response.py | 39 + .../types/app_events/__init__.py | 6 + .../types/app_events/catalog_list_response.py | 40 + .../app_events/catalog_retrieve_response.py | 40 + .../types/app_storage_usage_response.py | 26 + .../types/credential_list_response.py | 38 +- .../types/credentials/__init__.py | 1 + .../package_list_all_response.py} | 12 +- .../credentials/package_list_response.py | 38 +- .../types/credentials/packages/__init__.py | 1 - .../types/credentials/packages/credential.py | 38 - .../packages/credential_create_response.py | 36 +- .../packages/credential_delete_response.py | 36 +- .../packages/credential_retrieve_response.py | 38 +- .../credentials/field_create_response.py | 36 +- .../credentials/field_delete_response.py | 36 +- .../credentials/field_update_response.py | 36 +- .../types/device_create_params.py | 17 +- .../{device.py => device_create_response.py} | 4 +- .../types/device_list_response.py | 48 +- .../device_retrieve_capabilities_response.py | 62 + .../types/device_retrieve_response.py | 52 + .../types/device_set_name_response.py | 52 + .../types/device_wait_ready_response.py | 52 + src/mobilerun_sdk/types/devices/__init__.py | 21 +- .../devices/app_list_installs_response.py | 42 + .../devices/browser_execute_script_params.py | 21 + .../browser_execute_script_response.py | 21 + .../deep_link_execute_deep_link_params.py | 31 + .../types/devices/esim/__init__.py | 7 + .../types/devices/esim/apn_list_response.py | 35 + .../types/devices/esim/apn_select_params.py | 17 + .../types/devices/esim/apn_set_params.py | 29 + .../types/devices/esim_set_roaming_params.py | 15 + .../types/devices/esim_status_response.py | 35 + src/mobilerun_sdk/types/devices/file_info.py | 51 - .../types/devices/file_list_response.py | 47 +- .../kiosk_enable_params.py} | 12 +- .../media_session_activate_response.py | 26 + .../devices/media_session_create_params.py | 18 + .../devices/media_session_create_response.py | 32 + ...media_session_retrieve_current_response.py | 26 + .../types/devices/recording_list_params.py | 13 + .../types/devices/recording_list_response.py | 68 + .../types/devices/recording_start_params.py | 19 + .../types/devices/recording_start_response.py | 59 + .../devices/recording_status_response.py | 59 + .../types/devices/recording_stop_response.py | 59 + src/mobilerun_sdk/types/devices/rect.py | 11 - .../types/devices/state_ui_response.py | 10 +- .../types/devices/task_list_response.py | 14 +- .../types/esim_capacity_response.py | 17 + .../types/esim_confirm_payment_response.py | 69 + src/mobilerun_sdk/types/esim_create_params.py | 17 + .../types/esim_create_response.py | 69 + src/mobilerun_sdk/types/esim_import_params.py | 59 + .../types/esim_import_response.py | 204 +++ .../types/esim_install_params.py | 14 + .../types/esim_install_response.py | 69 + .../types/esim_install_status_response.py | 93 ++ src/mobilerun_sdk/types/esim_list_params.py | 20 + src/mobilerun_sdk/types/esim_list_response.py | 76 + .../types/esim_retrieve_response.py | 69 + .../types/esim_selector_response.py | 34 + src/mobilerun_sdk/types/esim_update_params.py | 24 + .../types/esim_update_response.py | 69 + src/mobilerun_sdk/types/esims/__init__.py | 8 + .../types/esims/message_list_params.py | 27 + .../types/esims/message_list_response.py | 48 + .../types/esims/message_send_params.py | 38 + .../types/esims/message_send_response.py | 41 + src/mobilerun_sdk/types/flow.py | 73 - .../types/message_list_params.py | 29 + .../types/message_list_response.py | 48 + src/mobilerun_sdk/types/messages/__init__.py | 8 + .../messages/conversation_list_params.py | 25 + .../messages/conversation_list_response.py | 49 + .../messages/conversation_mark_read_params.py | 24 + .../conversation_mark_read_response.py | 13 + .../types/notification_catalog_response.py | 29 + .../notification_get_preferences_response.py | 17 + .../notification_update_preferences_params.py | 14 + ...otification_update_preferences_response.py | 17 + .../types/number_countries_response.py | 27 + .../types/number_create_params.py | 29 + .../types/number_create_response.py | 22 + .../types/number_delete_response.py | 43 + src/mobilerun_sdk/types/number_list_params.py | 15 + .../types/number_list_response.py | 50 + .../types/number_purposes_response.py | 21 + .../types/number_retrieve_response.py | 43 + src/mobilerun_sdk/types/numbers/__init__.py | 6 + .../types/numbers/message_list_params.py | 21 + .../types/numbers/message_list_response.py | 59 + src/mobilerun_sdk/types/proxy_config.py | 42 - .../types/proxy_create_response.py | 25 +- .../types/proxy_delete_response.py | 25 +- .../types/proxy_list_response.py | 25 +- .../types/proxy_retrieve_response.py | 25 +- .../types/proxy_update_response.py | 25 +- src/mobilerun_sdk/types/shared/__init__.py | 2 +- src/mobilerun_sdk/types/shared/device_spec.py | 15 +- src/mobilerun_sdk/types/shared/socks5.py | 15 - .../types/shared/socks5_proxy_config.py | 25 + .../types/shared_params/__init__.py | 1 - .../types/shared_params/device_spec.py | 17 +- .../types/shared_params/socks5.py | 17 - src/mobilerun_sdk/types/store/__init__.py | 8 + .../store/app_add_to_workspace_response.py | 13 + .../types/store/app_list_params.py | 19 + .../types/store/app_list_response.py | 330 +++++ .../types/store/app_retrieve_response.py | 329 +++++ .../types/store_categories_response.py | 11 + src/mobilerun_sdk/types/task.py | 17 - .../types/task_get_status_response.py | 3 +- .../types/task_get_trajectory_response.py | 40 +- src/mobilerun_sdk/types/task_list_params.py | 3 +- src/mobilerun_sdk/types/task_list_response.py | 14 +- .../types/task_retrieve_response.py | 14 +- src/mobilerun_sdk/types/task_run_params.py | 11 +- src/mobilerun_sdk/types/task_run_response.py | 4 +- .../types/task_run_streamed_params.py | 11 +- src/mobilerun_sdk/types/task_status.py | 7 - src/mobilerun_sdk/types/tasks/__init__.py | 3 +- .../tasks/screenshot_retrieve_response.py | 10 + ...ponse.py => ui_state_retrieve_response.py} | 4 +- src/mobilerun_sdk/types/usage_result.py | 15 - src/mobilerun_sdk/types/workflows/__init__.py | 9 +- src/mobilerun_sdk/types/workflows/action.py | 39 - .../types/workflows/action_catalog_entry.py | 28 - .../workflows/action_catalog_list_response.py | 28 +- .../action_catalog_retrieve_response.py | 28 +- .../types/workflows/action_create_response.py | 39 +- .../types/workflows/action_list_response.py | 39 +- .../workflows/action_retrieve_response.py | 39 +- .../types/workflows/action_update_response.py | 39 +- .../types/workflows/event_dry_run_response.py | 67 +- ...ecution.py => execution_abort_response.py} | 8 +- .../workflows/execution_list_response.py | 36 +- .../workflows/execution_retrieve_response.py | 36 +- .../flow_child_action_input_param.py | 23 - .../types/workflows/flow_clone_response.py | 73 +- .../types/workflows/flow_create_params.py | 30 +- .../types/workflows/flow_create_response.py | 73 +- ...rrides_param.py => flow_dry_run_params.py} | 6 +- .../types/workflows/flow_dry_run_response.py | 74 + .../workflows/flow_list_repairs_response.py | 62 + .../types/workflows/flow_list_response.py | 73 +- .../types/workflows/flow_retrieve_response.py | 73 +- .../types/workflows/flow_unblock_response.py | 73 +- .../types/workflows/flow_update_response.py | 73 +- .../types/workflows/flows/__init__.py | 1 - .../workflows/flows/action_add_params.py | 30 +- .../workflows/flows/action_add_response.py | 33 +- .../workflows/flows/action_list_response.py | 33 +- .../workflows/flows/action_replace_params.py | 30 +- .../flows/action_replace_response.py | 33 +- .../types/workflows/flows/flow_action.py | 33 - .../types/workflows/trigger_update_params.py | 7 +- .../api_resources/app_events}/__init__.py | 2 - .../api_resources/app_events/test_catalog.py | 164 +++ .../credentials/test_packages.py | 62 +- tests/api_resources/devices/esim/__init__.py | 1 + tests/api_resources/devices/esim/test_apn.py | 430 ++++++ tests/api_resources/devices/test_apps.py | 375 +++++ tests/api_resources/devices/test_browser.py | 136 ++ tests/api_resources/devices/test_deep_link.py | 140 ++ tests/api_resources/devices/test_esim.py | 215 +++ tests/api_resources/devices/test_kiosk.py | 236 ++++ tests/api_resources/devices/test_location.py | 102 ++ .../devices/test_media_sessions.py | 440 ++++++ .../api_resources/devices/test_recordings.py | 759 ++++++++++ tests/api_resources/esims/__init__.py | 1 + tests/api_resources/esims/test_messages.py | 262 ++++ tests/api_resources/messages/__init__.py | 1 + .../messages/test_conversations.py | 188 +++ tests/api_resources/numbers/__init__.py | 1 + tests/api_resources/numbers/test_messages.py | 133 ++ tests/api_resources/store/__init__.py | 1 + tests/api_resources/store/test_apps.py | 270 ++++ tests/api_resources/tasks/test_screenshots.py | 14 +- tests/api_resources/tasks/test_ui_states.py | 14 +- tests/api_resources/test_agents.py | 80 ++ tests/api_resources/test_app_events.py | 192 +++ tests/api_resources/test_apps.py | 57 + tests/api_resources/test_devices.py | 310 ++++- tests/api_resources/test_esims.py | 933 +++++++++++++ tests/api_resources/test_messages.py | 110 ++ tests/api_resources/test_notifications.py | 208 +++ tests/api_resources/test_numbers.py | 463 +++++++ tests/api_resources/test_store.py | 80 ++ .../workflows/test_executions.py | 85 ++ tests/api_resources/workflows/test_flows.py | 188 +++ tests/test_client.py | 40 +- 245 files changed, 21294 insertions(+), 820 deletions(-) create mode 100644 src/mobilerun_sdk/resources/agents.py create mode 100644 src/mobilerun_sdk/resources/app_events/__init__.py create mode 100644 src/mobilerun_sdk/resources/app_events/app_events.py create mode 100644 src/mobilerun_sdk/resources/app_events/catalog.py create mode 100644 src/mobilerun_sdk/resources/devices/browser.py create mode 100644 src/mobilerun_sdk/resources/devices/deep_link.py create mode 100644 src/mobilerun_sdk/resources/devices/esim/__init__.py create mode 100644 src/mobilerun_sdk/resources/devices/esim/apn.py rename src/mobilerun_sdk/resources/devices/{ => esim}/esim.py (67%) create mode 100644 src/mobilerun_sdk/resources/devices/kiosk.py create mode 100644 src/mobilerun_sdk/resources/devices/media_sessions.py create mode 100644 src/mobilerun_sdk/resources/devices/recordings.py create mode 100644 src/mobilerun_sdk/resources/esims/__init__.py create mode 100644 src/mobilerun_sdk/resources/esims/esims.py create mode 100644 src/mobilerun_sdk/resources/esims/messages.py create mode 100644 src/mobilerun_sdk/resources/messages/__init__.py create mode 100644 src/mobilerun_sdk/resources/messages/conversations.py create mode 100644 src/mobilerun_sdk/resources/messages/messages.py create mode 100644 src/mobilerun_sdk/resources/notifications.py create mode 100644 src/mobilerun_sdk/resources/numbers/__init__.py create mode 100644 src/mobilerun_sdk/resources/numbers/messages.py create mode 100644 src/mobilerun_sdk/resources/numbers/numbers.py create mode 100644 src/mobilerun_sdk/resources/store/__init__.py create mode 100644 src/mobilerun_sdk/resources/store/apps.py create mode 100644 src/mobilerun_sdk/resources/store/store.py create mode 100644 src/mobilerun_sdk/types/agent_list_response.py create mode 100644 src/mobilerun_sdk/types/app_event_list_params.py create mode 100644 src/mobilerun_sdk/types/app_event_list_response.py create mode 100644 src/mobilerun_sdk/types/app_event_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/app_events/__init__.py create mode 100644 src/mobilerun_sdk/types/app_events/catalog_list_response.py create mode 100644 src/mobilerun_sdk/types/app_events/catalog_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/app_storage_usage_response.py rename src/mobilerun_sdk/types/{package_credentials.py => credentials/package_list_all_response.py} (55%) delete mode 100644 src/mobilerun_sdk/types/credentials/packages/credential.py rename src/mobilerun_sdk/types/{device.py => device_create_response.py} (95%) create mode 100644 src/mobilerun_sdk/types/device_retrieve_capabilities_response.py create mode 100644 src/mobilerun_sdk/types/device_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/device_set_name_response.py create mode 100644 src/mobilerun_sdk/types/device_wait_ready_response.py create mode 100644 src/mobilerun_sdk/types/devices/app_list_installs_response.py create mode 100644 src/mobilerun_sdk/types/devices/browser_execute_script_params.py create mode 100644 src/mobilerun_sdk/types/devices/browser_execute_script_response.py create mode 100644 src/mobilerun_sdk/types/devices/deep_link_execute_deep_link_params.py create mode 100644 src/mobilerun_sdk/types/devices/esim/__init__.py create mode 100644 src/mobilerun_sdk/types/devices/esim/apn_list_response.py create mode 100644 src/mobilerun_sdk/types/devices/esim/apn_select_params.py create mode 100644 src/mobilerun_sdk/types/devices/esim/apn_set_params.py create mode 100644 src/mobilerun_sdk/types/devices/esim_set_roaming_params.py create mode 100644 src/mobilerun_sdk/types/devices/esim_status_response.py delete mode 100644 src/mobilerun_sdk/types/devices/file_info.py rename src/mobilerun_sdk/types/{package_credentials_param.py => devices/kiosk_enable_params.py} (50%) create mode 100644 src/mobilerun_sdk/types/devices/media_session_activate_response.py create mode 100644 src/mobilerun_sdk/types/devices/media_session_create_params.py create mode 100644 src/mobilerun_sdk/types/devices/media_session_create_response.py create mode 100644 src/mobilerun_sdk/types/devices/media_session_retrieve_current_response.py create mode 100644 src/mobilerun_sdk/types/devices/recording_list_params.py create mode 100644 src/mobilerun_sdk/types/devices/recording_list_response.py create mode 100644 src/mobilerun_sdk/types/devices/recording_start_params.py create mode 100644 src/mobilerun_sdk/types/devices/recording_start_response.py create mode 100644 src/mobilerun_sdk/types/devices/recording_status_response.py create mode 100644 src/mobilerun_sdk/types/devices/recording_stop_response.py delete mode 100644 src/mobilerun_sdk/types/devices/rect.py create mode 100644 src/mobilerun_sdk/types/esim_capacity_response.py create mode 100644 src/mobilerun_sdk/types/esim_confirm_payment_response.py create mode 100644 src/mobilerun_sdk/types/esim_create_params.py create mode 100644 src/mobilerun_sdk/types/esim_create_response.py create mode 100644 src/mobilerun_sdk/types/esim_import_params.py create mode 100644 src/mobilerun_sdk/types/esim_import_response.py create mode 100644 src/mobilerun_sdk/types/esim_install_params.py create mode 100644 src/mobilerun_sdk/types/esim_install_response.py create mode 100644 src/mobilerun_sdk/types/esim_install_status_response.py create mode 100644 src/mobilerun_sdk/types/esim_list_params.py create mode 100644 src/mobilerun_sdk/types/esim_list_response.py create mode 100644 src/mobilerun_sdk/types/esim_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/esim_selector_response.py create mode 100644 src/mobilerun_sdk/types/esim_update_params.py create mode 100644 src/mobilerun_sdk/types/esim_update_response.py create mode 100644 src/mobilerun_sdk/types/esims/__init__.py create mode 100644 src/mobilerun_sdk/types/esims/message_list_params.py create mode 100644 src/mobilerun_sdk/types/esims/message_list_response.py create mode 100644 src/mobilerun_sdk/types/esims/message_send_params.py create mode 100644 src/mobilerun_sdk/types/esims/message_send_response.py delete mode 100644 src/mobilerun_sdk/types/flow.py create mode 100644 src/mobilerun_sdk/types/message_list_params.py create mode 100644 src/mobilerun_sdk/types/message_list_response.py create mode 100644 src/mobilerun_sdk/types/messages/__init__.py create mode 100644 src/mobilerun_sdk/types/messages/conversation_list_params.py create mode 100644 src/mobilerun_sdk/types/messages/conversation_list_response.py create mode 100644 src/mobilerun_sdk/types/messages/conversation_mark_read_params.py create mode 100644 src/mobilerun_sdk/types/messages/conversation_mark_read_response.py create mode 100644 src/mobilerun_sdk/types/notification_catalog_response.py create mode 100644 src/mobilerun_sdk/types/notification_get_preferences_response.py create mode 100644 src/mobilerun_sdk/types/notification_update_preferences_params.py create mode 100644 src/mobilerun_sdk/types/notification_update_preferences_response.py create mode 100644 src/mobilerun_sdk/types/number_countries_response.py create mode 100644 src/mobilerun_sdk/types/number_create_params.py create mode 100644 src/mobilerun_sdk/types/number_create_response.py create mode 100644 src/mobilerun_sdk/types/number_delete_response.py create mode 100644 src/mobilerun_sdk/types/number_list_params.py create mode 100644 src/mobilerun_sdk/types/number_list_response.py create mode 100644 src/mobilerun_sdk/types/number_purposes_response.py create mode 100644 src/mobilerun_sdk/types/number_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/numbers/__init__.py create mode 100644 src/mobilerun_sdk/types/numbers/message_list_params.py create mode 100644 src/mobilerun_sdk/types/numbers/message_list_response.py delete mode 100644 src/mobilerun_sdk/types/proxy_config.py delete mode 100644 src/mobilerun_sdk/types/shared/socks5.py create mode 100644 src/mobilerun_sdk/types/shared/socks5_proxy_config.py delete mode 100644 src/mobilerun_sdk/types/shared_params/socks5.py create mode 100644 src/mobilerun_sdk/types/store/__init__.py create mode 100644 src/mobilerun_sdk/types/store/app_add_to_workspace_response.py create mode 100644 src/mobilerun_sdk/types/store/app_list_params.py create mode 100644 src/mobilerun_sdk/types/store/app_list_response.py create mode 100644 src/mobilerun_sdk/types/store/app_retrieve_response.py create mode 100644 src/mobilerun_sdk/types/store_categories_response.py delete mode 100644 src/mobilerun_sdk/types/task.py delete mode 100644 src/mobilerun_sdk/types/task_status.py create mode 100644 src/mobilerun_sdk/types/tasks/screenshot_retrieve_response.py rename src/mobilerun_sdk/types/tasks/{media_response.py => ui_state_retrieve_response.py} (67%) delete mode 100644 src/mobilerun_sdk/types/usage_result.py delete mode 100644 src/mobilerun_sdk/types/workflows/action.py delete mode 100644 src/mobilerun_sdk/types/workflows/action_catalog_entry.py rename src/mobilerun_sdk/types/workflows/{flow_execution.py => execution_abort_response.py} (91%) delete mode 100644 src/mobilerun_sdk/types/workflows/flow_child_action_input_param.py rename src/mobilerun_sdk/types/workflows/{flow_action_overrides_param.py => flow_dry_run_params.py} (60%) create mode 100644 src/mobilerun_sdk/types/workflows/flow_dry_run_response.py create mode 100644 src/mobilerun_sdk/types/workflows/flow_list_repairs_response.py delete mode 100644 src/mobilerun_sdk/types/workflows/flows/flow_action.py rename {src/mobilerun_sdk/types/workflows/events => tests/api_resources/app_events}/__init__.py (70%) create mode 100644 tests/api_resources/app_events/test_catalog.py create mode 100644 tests/api_resources/devices/esim/__init__.py create mode 100644 tests/api_resources/devices/esim/test_apn.py create mode 100644 tests/api_resources/devices/test_browser.py create mode 100644 tests/api_resources/devices/test_deep_link.py create mode 100644 tests/api_resources/devices/test_kiosk.py create mode 100644 tests/api_resources/devices/test_media_sessions.py create mode 100644 tests/api_resources/devices/test_recordings.py create mode 100644 tests/api_resources/esims/__init__.py create mode 100644 tests/api_resources/esims/test_messages.py create mode 100644 tests/api_resources/messages/__init__.py create mode 100644 tests/api_resources/messages/test_conversations.py create mode 100644 tests/api_resources/numbers/__init__.py create mode 100644 tests/api_resources/numbers/test_messages.py create mode 100644 tests/api_resources/store/__init__.py create mode 100644 tests/api_resources/store/test_apps.py create mode 100644 tests/api_resources/test_agents.py create mode 100644 tests/api_resources/test_app_events.py create mode 100644 tests/api_resources/test_esims.py create mode 100644 tests/api_resources/test_messages.py create mode 100644 tests/api_resources/test_notifications.py create mode 100644 tests/api_resources/test_numbers.py create mode 100644 tests/api_resources/test_store.py diff --git a/.stats.yml b/.stats.yml index a1b6df07..fa7630c7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1 @@ -configured_endpoints: 150 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/droidrun/droidrun-cloud-7cec88e5c0ed1f90579cbbf740bb13588e96f075f10beec368d52a977260a9d9.yml -openapi_spec_hash: 91e423c7355759d210dbbaa040fc1313 -config_hash: 0636636df2adbdea4b2e982ab5c858d4 +configured_endpoints: 217 diff --git a/README.md b/README.md index 73b8b1d9..84e80afa 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,18 @@ Use the Mobilerun MCP Server to enable AI assistants to interact with this API, ## Documentation -The REST API documentation can be found on [docs.mobilerun.ai](https://docs.mobilerun.ai). The full API of this library can be found in [api.md](api.md). +The full API of this library can be found in [api.md](api.md). ## Installation ```sh -# install from PyPI -pip install mobilerun-sdk +# install from the production repo +pip install git+ssh://git@github.com/droidrun/mobilerun-sdk-python.git ``` +> [!NOTE] +> Once this package is [published to PyPI](https://www.stainless.com/docs/guides/publish), this will become: `pip install mobilerun-sdk` + ## Usage The full API of this library can be found in [api.md](api.md). @@ -41,11 +44,11 @@ client = Mobilerun( api_key=os.environ.get("MOBILERUN_CLOUD_API_KEY"), # This is the default and can be omitted ) -tasks = client.tasks.list() -print(tasks.items) +devices = client.devices.list() +print(devices.items) ``` -While you can provide a `api_key` keyword argument, +While you can provide an `api_key` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to add `MOBILERUN_CLOUD_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. @@ -65,8 +68,8 @@ client = AsyncMobilerun( async def main() -> None: - tasks = await client.tasks.list() - print(tasks.items) + devices = await client.devices.list() + print(devices.items) asyncio.run(main()) @@ -81,8 +84,8 @@ By default, the async client uses `httpx` for HTTP requests. However, for improv You can enable this by installing `aiohttp`: ```sh -# install from PyPI -pip install mobilerun-sdk[aiohttp] +# install from the production repo +pip install 'mobilerun-sdk[aiohttp] @ git+ssh://git@github.com/droidrun/mobilerun-sdk-python.git' ``` Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: @@ -99,8 +102,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: - tasks = await client.tasks.list() - print(tasks.items) + devices = await client.devices.list() + print(devices.items) asyncio.run(main()) @@ -172,7 +175,7 @@ from mobilerun_sdk import Mobilerun client = Mobilerun() try: - client.tasks.list() + client.devices.list() except mobilerun_sdk.APIConnectionError as e: print("The server could not be reached") print(e.__cause__) # an underlying Exception, likely raised within httpx. @@ -215,7 +218,7 @@ client = Mobilerun( ) # Or, configure per-request: -client.with_options(max_retries=5).tasks.list() +client.with_options(max_retries=5).devices.list() ``` ### Timeouts @@ -238,7 +241,7 @@ client = Mobilerun( ) # Override per-request: -client.with_options(timeout=5.0).tasks.list() +client.with_options(timeout=5.0).devices.list() ``` On timeout, an `APITimeoutError` is thrown. @@ -279,11 +282,11 @@ The "raw" Response object can be accessed by prefixing `.with_raw_response.` to from mobilerun_sdk import Mobilerun client = Mobilerun() -response = client.tasks.with_raw_response.list() +response = client.devices.with_raw_response.list() print(response.headers.get('X-My-Header')) -task = response.parse() # get the object that `tasks.list()` would have returned -print(task.items) +device = response.parse() # get the object that `devices.list()` would have returned +print(device.items) ``` These methods return an [`APIResponse`](https://github.com/droidrun/mobilerun-sdk-python/tree/main/src/mobilerun_sdk/_response.py) object. @@ -297,7 +300,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.list() as response: +with client.devices.with_streaming_response.list() as response: print(response.headers.get("X-My-Header")) for line in response.iter_lines(): diff --git a/SECURITY.md b/SECURITY.md index 6aec6b4c..df804343 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -20,7 +20,7 @@ or products provided by Mobilerun, please follow the respective company's securi ### Mobilerun Terms and Policies -Please contact support@droidrun.ai for any questions or concerns regarding the security of our services. +Please contact lucius@droidrun.ai for any questions or concerns regarding the security of our services. --- diff --git a/api.md b/api.md index ed2f3fb6..444c197a 100644 --- a/api.md +++ b/api.md @@ -10,7 +10,7 @@ from mobilerun_sdk.types import ( Pagination, PaginationMeta, PermissionSet, - Socks5, + Socks5ProxyConfig, ) ``` @@ -27,6 +27,7 @@ from mobilerun_sdk.types import ( AppCreateSignedUploadURLResponse, AppListVersionsResponse, AppMarkFailedResponse, + AppStorageUsageResponse, ) ``` @@ -39,6 +40,7 @@ Methods: - client.apps.create_signed_upload_url(\*\*params) -> AppCreateSignedUploadURLResponse - client.apps.list_versions(id) -> AppListVersionsResponse - client.apps.mark_failed(id) -> AppMarkFailedResponse +- client.apps.storage_usage() -> AppStorageUsageResponse # Carriers @@ -81,13 +83,18 @@ Methods: Types: ```python -from mobilerun_sdk.types.credentials import PackageCreateResponse, PackageListResponse +from mobilerun_sdk.types.credentials import ( + PackageCreateResponse, + PackageListResponse, + PackageListAllResponse, +) ``` Methods: - client.credentials.packages.create(\*\*params) -> PackageCreateResponse - client.credentials.packages.list(package_name) -> PackageListResponse +- client.credentials.packages.list_all() -> PackageListAllResponse ### Credentials @@ -95,7 +102,6 @@ Types: ```python from mobilerun_sdk.types.credentials.packages import ( - Credential, CredentialCreateResponse, CredentialRetrieveResponse, CredentialDeleteResponse, @@ -132,25 +138,32 @@ Types: ```python from mobilerun_sdk.types import ( - Device, + DeviceCreateResponse, + DeviceRetrieveResponse, DeviceListResponse, DeviceCountResponse, DeviceFingerprintResponse, + DeviceRetrieveCapabilitiesResponse, + DeviceSetNameResponse, + DeviceWaitReadyResponse, ) ``` Methods: -- client.devices.create(\*\*params) -> Device -- client.devices.retrieve(device_id) -> Device +- client.devices.create(\*\*params) -> DeviceCreateResponse +- client.devices.retrieve(device_id) -> DeviceRetrieveResponse - client.devices.list(\*\*params) -> DeviceListResponse - client.devices.count() -> DeviceCountResponse - client.devices.fingerprint(device_id) -> DeviceFingerprintResponse - client.devices.reboot(device_id) -> None - client.devices.reset(device_id) -> None -- client.devices.set_name(device_id, \*\*params) -> Device +- client.devices.resume(device_id) -> None +- client.devices.retrieve_capabilities(device_id) -> DeviceRetrieveCapabilitiesResponse +- client.devices.set_name(device_id, \*\*params) -> DeviceSetNameResponse +- client.devices.stop(device_id) -> None - client.devices.terminate(device_id, \*\*params) -> None -- client.devices.wait_ready(device_id) -> Device +- client.devices.wait_ready(device_id) -> DeviceWaitReadyResponse ## Actions @@ -173,14 +186,17 @@ Methods: Types: ```python -from mobilerun_sdk.types.devices import AppListResponse +from mobilerun_sdk.types.devices import AppListResponse, AppListInstallsResponse ``` Methods: - client.devices.apps.list(device_id, \*\*params) -> Optional[AppListResponse] - client.devices.apps.delete(package_name, \*, device_id) -> None +- client.devices.apps.grant_permission(permission, \*, device_id, package_name) -> None - client.devices.apps.install(device_id, \*\*params) -> None +- client.devices.apps.list_installs(device_id) -> AppListInstallsResponse +- client.devices.apps.revoke_permission(permission, \*, device_id, package_name) -> None - client.devices.apps.start(package_name, \*, device_id, \*\*params) -> None - client.devices.apps.stop(package_name, \*, device_id, \*\*params) -> None @@ -189,22 +205,38 @@ Methods: Types: ```python -from mobilerun_sdk.types.devices import EsimListResponse, EsimActivateResponse +from mobilerun_sdk.types.devices import EsimListResponse, EsimActivateResponse, EsimStatusResponse ``` Methods: -- client.devices.esim.list(device_id) -> Optional[EsimListResponse] -- client.devices.esim.activate(device_id, \*\*params) -> EsimActivateResponse -- client.devices.esim.enable(device_id, \*\*params) -> None -- client.devices.esim.remove(device_id, \*\*params) -> None +- client.devices.esim.list(device_id) -> Optional[EsimListResponse] +- client.devices.esim.activate(device_id, \*\*params) -> EsimActivateResponse +- client.devices.esim.enable(device_id, \*\*params) -> None +- client.devices.esim.remove(device_id, \*\*params) -> None +- client.devices.esim.set_roaming(device_id, \*\*params) -> None +- client.devices.esim.status(device_id) -> Optional[EsimStatusResponse] + +### Apn + +Types: + +```python +from mobilerun_sdk.types.devices.esim import ApnListResponse +``` + +Methods: + +- client.devices.esim.apn.list(device_id) -> Optional[ApnListResponse] +- client.devices.esim.apn.select(device_id, \*\*params) -> None +- client.devices.esim.apn.set(device_id, \*\*params) -> None ## Files Types: ```python -from mobilerun_sdk.types.devices import FileInfo, FileListResponse, FileDownloadResponse +from mobilerun_sdk.types.devices import FileListResponse, FileDownloadResponse ``` Methods: @@ -227,6 +259,7 @@ Methods: Methods: - client.devices.location.get(device_id) -> Location +- client.devices.location.reset(device_id) -> None - client.devices.location.set(device_id, \*\*params) -> None ## Packages @@ -268,7 +301,6 @@ Types: ```python from mobilerun_sdk.types.devices import ( A11YNode, - Rect, StateScreenshotResponse, StateTimeResponse, StateUiResponse, @@ -319,6 +351,73 @@ Methods: - client.devices.language.get(device_id) -> LanguageGetResponse - client.devices.language.set(device_id, \*\*params) -> None +## DeepLink + +Methods: + +- client.devices.deep_link.execute_deep_link(device_id, \*\*params) -> None + +## Browser + +Types: + +```python +from mobilerun_sdk.types.devices import BrowserExecuteScriptResponse +``` + +Methods: + +- client.devices.browser.execute_script(device_id, \*\*params) -> BrowserExecuteScriptResponse + +## Kiosk + +Methods: + +- client.devices.kiosk.disable(device_id) -> None +- client.devices.kiosk.enable(device_id, \*\*params) -> None + +## MediaSessions + +Types: + +```python +from mobilerun_sdk.types.devices import ( + MediaSessionCreateResponse, + MediaSessionActivateResponse, + MediaSessionRetrieveCurrentResponse, +) +``` + +Methods: + +- client.devices.media_sessions.create(device_id, \*\*params) -> MediaSessionCreateResponse +- client.devices.media_sessions.delete(session_id, \*, device_id) -> None +- client.devices.media_sessions.activate(session_id, \*, device_id) -> MediaSessionActivateResponse +- client.devices.media_sessions.retrieve_current(device_id) -> MediaSessionRetrieveCurrentResponse + +## Recordings + +Types: + +```python +from mobilerun_sdk.types.devices import ( + RecordingListResponse, + RecordingStartResponse, + RecordingStatusResponse, + RecordingStopResponse, +) +``` + +Methods: + +- client.devices.recordings.list(device_id, \*\*params) -> Optional[RecordingListResponse] +- client.devices.recordings.delete(recording_id, \*, device_id) -> None +- client.devices.recordings.start(device_id, \*\*params) -> RecordingStartResponse +- client.devices.recordings.status(recording_id, \*, device_id) -> RecordingStatusResponse +- client.devices.recordings.stop(recording_id, \*, device_id) -> RecordingStopResponse +- client.devices.recordings.trajectory(recording_id, \*, device_id) -> None +- client.devices.recordings.video(recording_id, \*, device_id) -> None + # Models Types: @@ -359,7 +458,6 @@ Types: ```python from mobilerun_sdk.types import ( - ProxyConfig, ProxyCreateResponse, ProxyRetrieveResponse, ProxyUpdateResponse, @@ -444,10 +542,6 @@ Types: ```python from mobilerun_sdk.types import ( - PackageCredentials, - Task, - TaskStatus, - UsageResult, TaskRetrieveResponse, TaskListResponse, TaskGetStatusResponse, @@ -475,12 +569,12 @@ Methods: Types: ```python -from mobilerun_sdk.types.tasks import MediaResponse, ScreenshotListResponse +from mobilerun_sdk.types.tasks import ScreenshotRetrieveResponse, ScreenshotListResponse ``` Methods: -- client.tasks.screenshots.retrieve(index, \*, task_id) -> MediaResponse +- client.tasks.screenshots.retrieve(index, \*, task_id) -> ScreenshotRetrieveResponse - client.tasks.screenshots.list(task_id) -> ScreenshotListResponse ## UiStates @@ -488,22 +582,16 @@ Methods: Types: ```python -from mobilerun_sdk.types.tasks import UiStateListResponse +from mobilerun_sdk.types.tasks import UiStateRetrieveResponse, UiStateListResponse ``` Methods: -- client.tasks.ui_states.retrieve(index, \*, task_id) -> MediaResponse +- client.tasks.ui_states.retrieve(index, \*, task_id) -> UiStateRetrieveResponse - client.tasks.ui_states.list(task_id) -> UiStateListResponse # Workflows -Types: - -```python -from mobilerun_sdk.types import Flow -``` - ## Triggers Types: @@ -533,11 +621,7 @@ Methods: Types: ```python -from mobilerun_sdk.types.workflows import ( - ActionCatalogEntry, - ActionCatalogRetrieveResponse, - ActionCatalogListResponse, -) +from mobilerun_sdk.types.workflows import ActionCatalogRetrieveResponse, ActionCatalogListResponse ``` Methods: @@ -551,7 +635,6 @@ Types: ```python from mobilerun_sdk.types.workflows import ( - Action, ActionCreateResponse, ActionRetrieveResponse, ActionUpdateResponse, @@ -587,14 +670,14 @@ Types: ```python from mobilerun_sdk.types.workflows import ( - FlowActionOverrides, - FlowChildActionInput, FlowCreateResponse, FlowRetrieveResponse, FlowUpdateResponse, FlowListResponse, FlowDeleteResponse, FlowCloneResponse, + FlowDryRunResponse, + FlowListRepairsResponse, FlowUnblockResponse, ) ``` @@ -607,6 +690,8 @@ Methods: - client.workflows.flows.list(\*\*params) -> FlowListResponse - client.workflows.flows.delete(flow_id) -> FlowDeleteResponse - client.workflows.flows.clone(flow_id, \*\*params) -> FlowCloneResponse +- client.workflows.flows.dry_run(flow_id, \*\*params) -> FlowDryRunResponse +- client.workflows.flows.list_repairs(flow_id) -> FlowListRepairsResponse - client.workflows.flows.unblock(flow_id) -> FlowUnblockResponse ### Actions @@ -615,7 +700,6 @@ Types: ```python from mobilerun_sdk.types.workflows.flows import ( - FlowAction, ActionListResponse, ActionAddResponse, ActionRemoveResponse, @@ -649,9 +733,9 @@ Types: ```python from mobilerun_sdk.types.workflows import ( - FlowExecution, ExecutionRetrieveResponse, ExecutionListResponse, + ExecutionAbortResponse, ExecutionGetMetricsResponse, ) ``` @@ -660,6 +744,7 @@ Methods: - client.workflows.executions.retrieve(execution_id) -> ExecutionRetrieveResponse - client.workflows.executions.list(\*\*params) -> ExecutionListResponse +- client.workflows.executions.abort(execution_id) -> ExecutionAbortResponse - client.workflows.executions.get_metrics(\*\*params) -> ExecutionGetMetricsResponse ## Timezones @@ -720,3 +805,196 @@ Methods: - client.webhooks.deliveries.list_for_webhook(id, \*\*params) -> DeliveryListForWebhookResponse - client.webhooks.deliveries.retrieve_attempts(delivery_id, \*, id) -> DeliveryRetrieveAttemptsResponse - client.webhooks.deliveries.stats(\*\*params) -> DeliveryStatsResponse + +# Agents + +Types: + +```python +from mobilerun_sdk.types import AgentListResponse +``` + +Methods: + +- client.agents.list() -> AgentListResponse + +# AppEvents + +Types: + +```python +from mobilerun_sdk.types import AppEventRetrieveResponse, AppEventListResponse +``` + +Methods: + +- client.app_events.retrieve(id) -> AppEventRetrieveResponse +- client.app_events.list(\*\*params) -> AppEventListResponse + +## Catalog + +Types: + +```python +from mobilerun_sdk.types.app_events import CatalogRetrieveResponse, CatalogListResponse +``` + +Methods: + +- client.app_events.catalog.retrieve(app_event_type) -> CatalogRetrieveResponse +- client.app_events.catalog.list() -> CatalogListResponse + +# Notifications + +Types: + +```python +from mobilerun_sdk.types import ( + NotificationCatalogResponse, + NotificationGetPreferencesResponse, + NotificationUpdatePreferencesResponse, +) +``` + +Methods: + +- client.notifications.catalog() -> NotificationCatalogResponse +- client.notifications.get_preferences() -> NotificationGetPreferencesResponse +- client.notifications.update_preferences(\*\*params) -> NotificationUpdatePreferencesResponse + +# Esims + +Types: + +```python +from mobilerun_sdk.types import ( + EsimCreateResponse, + EsimRetrieveResponse, + EsimUpdateResponse, + EsimListResponse, + EsimCapacityResponse, + EsimConfirmPaymentResponse, + EsimImportResponse, + EsimInstallResponse, + EsimInstallStatusResponse, + EsimSelectorResponse, +) +``` + +Methods: + +- client.esims.create(\*\*params) -> EsimCreateResponse +- client.esims.retrieve(id) -> EsimRetrieveResponse +- client.esims.update(id, \*\*params) -> EsimUpdateResponse +- client.esims.list(\*\*params) -> EsimListResponse +- client.esims.delete(id) -> None +- client.esims.capacity() -> EsimCapacityResponse +- client.esims.confirm_payment(id) -> EsimConfirmPaymentResponse +- client.esims.import\_(\*\*params) -> EsimImportResponse +- client.esims.install(id, \*\*params) -> EsimInstallResponse +- client.esims.install_status(id) -> EsimInstallStatusResponse +- client.esims.selector() -> EsimSelectorResponse + +## Messages + +Types: + +```python +from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse +``` + +Methods: + +- client.esims.messages.list(id, \*\*params) -> MessageListResponse +- client.esims.messages.send(id, \*\*params) -> MessageSendResponse + +# Messages + +Types: + +```python +from mobilerun_sdk.types import MessageListResponse +``` + +Methods: + +- client.messages.list(\*\*params) -> MessageListResponse + +## Conversations + +Types: + +```python +from mobilerun_sdk.types.messages import ConversationListResponse, ConversationMarkReadResponse +``` + +Methods: + +- client.messages.conversations.list(\*\*params) -> ConversationListResponse +- client.messages.conversations.mark_read(\*\*params) -> ConversationMarkReadResponse + +# Numbers + +Types: + +```python +from mobilerun_sdk.types import ( + NumberCreateResponse, + NumberRetrieveResponse, + NumberListResponse, + NumberDeleteResponse, + NumberCountriesResponse, + NumberPurposesResponse, +) +``` + +Methods: + +- client.numbers.create(\*\*params) -> NumberCreateResponse +- client.numbers.retrieve(id) -> NumberRetrieveResponse +- client.numbers.list(\*\*params) -> NumberListResponse +- client.numbers.delete(id) -> NumberDeleteResponse +- client.numbers.countries() -> NumberCountriesResponse +- client.numbers.purposes() -> NumberPurposesResponse + +## Messages + +Types: + +```python +from mobilerun_sdk.types.numbers import MessageListResponse +``` + +Methods: + +- client.numbers.messages.list(id, \*\*params) -> MessageListResponse + +# Store + +Types: + +```python +from mobilerun_sdk.types import StoreCategoriesResponse +``` + +Methods: + +- client.store.categories() -> StoreCategoriesResponse + +## Apps + +Types: + +```python +from mobilerun_sdk.types.store import ( + AppRetrieveResponse, + AppListResponse, + AppAddToWorkspaceResponse, +) +``` + +Methods: + +- client.store.apps.retrieve(app_id) -> AppRetrieveResponse +- client.store.apps.list(\*\*params) -> AppListResponse +- client.store.apps.add_to_workspace(app_id) -> AppAddToWorkspaceResponse diff --git a/pyproject.toml b/pyproject.toml index f34d3f64..f5a20606 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "The official Python library for the mobilerun API" dynamic = ["readme"] license = "Apache-2.0" authors = [ -{ name = "Mobilerun", email = "support@droidrun.ai" }, +{ name = "Mobilerun", email = "lucius@droidrun.ai" }, ] dependencies = [ diff --git a/release-please-config.json b/release-please-config.json index cae97fd1..c7f62034 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -2,7 +2,7 @@ "packages": { ".": {} }, - "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", "include-v-in-tag": true, "include-component-in-tag": false, "bump-minor-pre-major": true, diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 74d687ed..90aa8f6a 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -20,7 +20,7 @@ UPLOAD_RESPONSE=$(curl -v -X PUT \ if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/droidrun-cloud-python/$SHA/$FILENAME'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/mobilerun-sdk-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 diff --git a/src/mobilerun_sdk/_client.py b/src/mobilerun_sdk/_client.py index 2ac53045..218abfaf 100644 --- a/src/mobilerun_sdk/_client.py +++ b/src/mobilerun_sdk/_client.py @@ -38,27 +38,41 @@ if TYPE_CHECKING: from .resources import ( apps, + esims, + store, tasks, + agents, models, connect, devices, + numbers, proxies, carriers, + messages, profiles, webhooks, workflows, + app_events, credentials, + notifications, ) from .resources.apps import AppsResource, AsyncAppsResource + from .resources.agents import AgentsResource, AsyncAgentsResource from .resources.models import ModelsResource, AsyncModelsResource from .resources.proxies import ProxiesResource, AsyncProxiesResource from .resources.carriers import CarriersResource, AsyncCarriersResource from .resources.profiles import ProfilesResource, AsyncProfilesResource + from .resources.esims.esims import EsimsResource, AsyncEsimsResource + from .resources.store.store import StoreResource, AsyncStoreResource from .resources.tasks.tasks import TasksResource, AsyncTasksResource + from .resources.notifications import NotificationsResource, AsyncNotificationsResource from .resources.connect.connect import ConnectResource, AsyncConnectResource from .resources.devices.devices import DevicesResource, AsyncDevicesResource + from .resources.numbers.numbers import NumbersResource, AsyncNumbersResource + from .resources.messages.messages import MessagesResource, AsyncMessagesResource from .resources.webhooks.webhooks import WebhooksResource, AsyncWebhooksResource from .resources.workflows.workflows import WorkflowsResource, AsyncWorkflowsResource + from .resources.app_events.app_events import AppEventsResource, AsyncAppEventsResource from .resources.credentials.credentials import CredentialsResource, AsyncCredentialsResource __all__ = [ @@ -201,6 +215,48 @@ def webhooks(self) -> WebhooksResource: return WebhooksResource(self) + @cached_property + def agents(self) -> AgentsResource: + from .resources.agents import AgentsResource + + return AgentsResource(self) + + @cached_property + def app_events(self) -> AppEventsResource: + from .resources.app_events import AppEventsResource + + return AppEventsResource(self) + + @cached_property + def notifications(self) -> NotificationsResource: + from .resources.notifications import NotificationsResource + + return NotificationsResource(self) + + @cached_property + def esims(self) -> EsimsResource: + from .resources.esims import EsimsResource + + return EsimsResource(self) + + @cached_property + def messages(self) -> MessagesResource: + from .resources.messages import MessagesResource + + return MessagesResource(self) + + @cached_property + def numbers(self) -> NumbersResource: + from .resources.numbers import NumbersResource + + return NumbersResource(self) + + @cached_property + def store(self) -> StoreResource: + from .resources.store import StoreResource + + return StoreResource(self) + @cached_property def with_raw_response(self) -> MobilerunWithRawResponse: return MobilerunWithRawResponse(self) @@ -453,6 +509,48 @@ def webhooks(self) -> AsyncWebhooksResource: return AsyncWebhooksResource(self) + @cached_property + def agents(self) -> AsyncAgentsResource: + from .resources.agents import AsyncAgentsResource + + return AsyncAgentsResource(self) + + @cached_property + def app_events(self) -> AsyncAppEventsResource: + from .resources.app_events import AsyncAppEventsResource + + return AsyncAppEventsResource(self) + + @cached_property + def notifications(self) -> AsyncNotificationsResource: + from .resources.notifications import AsyncNotificationsResource + + return AsyncNotificationsResource(self) + + @cached_property + def esims(self) -> AsyncEsimsResource: + from .resources.esims import AsyncEsimsResource + + return AsyncEsimsResource(self) + + @cached_property + def messages(self) -> AsyncMessagesResource: + from .resources.messages import AsyncMessagesResource + + return AsyncMessagesResource(self) + + @cached_property + def numbers(self) -> AsyncNumbersResource: + from .resources.numbers import AsyncNumbersResource + + return AsyncNumbersResource(self) + + @cached_property + def store(self) -> AsyncStoreResource: + from .resources.store import AsyncStoreResource + + return AsyncStoreResource(self) + @cached_property def with_raw_response(self) -> AsyncMobilerunWithRawResponse: return AsyncMobilerunWithRawResponse(self) @@ -651,6 +749,48 @@ def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse: return WebhooksResourceWithRawResponse(self._client.webhooks) + @cached_property + def agents(self) -> agents.AgentsResourceWithRawResponse: + from .resources.agents import AgentsResourceWithRawResponse + + return AgentsResourceWithRawResponse(self._client.agents) + + @cached_property + def app_events(self) -> app_events.AppEventsResourceWithRawResponse: + from .resources.app_events import AppEventsResourceWithRawResponse + + return AppEventsResourceWithRawResponse(self._client.app_events) + + @cached_property + def notifications(self) -> notifications.NotificationsResourceWithRawResponse: + from .resources.notifications import NotificationsResourceWithRawResponse + + return NotificationsResourceWithRawResponse(self._client.notifications) + + @cached_property + def esims(self) -> esims.EsimsResourceWithRawResponse: + from .resources.esims import EsimsResourceWithRawResponse + + return EsimsResourceWithRawResponse(self._client.esims) + + @cached_property + def messages(self) -> messages.MessagesResourceWithRawResponse: + from .resources.messages import MessagesResourceWithRawResponse + + return MessagesResourceWithRawResponse(self._client.messages) + + @cached_property + def numbers(self) -> numbers.NumbersResourceWithRawResponse: + from .resources.numbers import NumbersResourceWithRawResponse + + return NumbersResourceWithRawResponse(self._client.numbers) + + @cached_property + def store(self) -> store.StoreResourceWithRawResponse: + from .resources.store import StoreResourceWithRawResponse + + return StoreResourceWithRawResponse(self._client.store) + class AsyncMobilerunWithRawResponse: _client: AsyncMobilerun @@ -726,6 +866,48 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse: return AsyncWebhooksResourceWithRawResponse(self._client.webhooks) + @cached_property + def agents(self) -> agents.AsyncAgentsResourceWithRawResponse: + from .resources.agents import AsyncAgentsResourceWithRawResponse + + return AsyncAgentsResourceWithRawResponse(self._client.agents) + + @cached_property + def app_events(self) -> app_events.AsyncAppEventsResourceWithRawResponse: + from .resources.app_events import AsyncAppEventsResourceWithRawResponse + + return AsyncAppEventsResourceWithRawResponse(self._client.app_events) + + @cached_property + def notifications(self) -> notifications.AsyncNotificationsResourceWithRawResponse: + from .resources.notifications import AsyncNotificationsResourceWithRawResponse + + return AsyncNotificationsResourceWithRawResponse(self._client.notifications) + + @cached_property + def esims(self) -> esims.AsyncEsimsResourceWithRawResponse: + from .resources.esims import AsyncEsimsResourceWithRawResponse + + return AsyncEsimsResourceWithRawResponse(self._client.esims) + + @cached_property + def messages(self) -> messages.AsyncMessagesResourceWithRawResponse: + from .resources.messages import AsyncMessagesResourceWithRawResponse + + return AsyncMessagesResourceWithRawResponse(self._client.messages) + + @cached_property + def numbers(self) -> numbers.AsyncNumbersResourceWithRawResponse: + from .resources.numbers import AsyncNumbersResourceWithRawResponse + + return AsyncNumbersResourceWithRawResponse(self._client.numbers) + + @cached_property + def store(self) -> store.AsyncStoreResourceWithRawResponse: + from .resources.store import AsyncStoreResourceWithRawResponse + + return AsyncStoreResourceWithRawResponse(self._client.store) + class MobilerunWithStreamedResponse: _client: Mobilerun @@ -801,6 +983,48 @@ def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse: return WebhooksResourceWithStreamingResponse(self._client.webhooks) + @cached_property + def agents(self) -> agents.AgentsResourceWithStreamingResponse: + from .resources.agents import AgentsResourceWithStreamingResponse + + return AgentsResourceWithStreamingResponse(self._client.agents) + + @cached_property + def app_events(self) -> app_events.AppEventsResourceWithStreamingResponse: + from .resources.app_events import AppEventsResourceWithStreamingResponse + + return AppEventsResourceWithStreamingResponse(self._client.app_events) + + @cached_property + def notifications(self) -> notifications.NotificationsResourceWithStreamingResponse: + from .resources.notifications import NotificationsResourceWithStreamingResponse + + return NotificationsResourceWithStreamingResponse(self._client.notifications) + + @cached_property + def esims(self) -> esims.EsimsResourceWithStreamingResponse: + from .resources.esims import EsimsResourceWithStreamingResponse + + return EsimsResourceWithStreamingResponse(self._client.esims) + + @cached_property + def messages(self) -> messages.MessagesResourceWithStreamingResponse: + from .resources.messages import MessagesResourceWithStreamingResponse + + return MessagesResourceWithStreamingResponse(self._client.messages) + + @cached_property + def numbers(self) -> numbers.NumbersResourceWithStreamingResponse: + from .resources.numbers import NumbersResourceWithStreamingResponse + + return NumbersResourceWithStreamingResponse(self._client.numbers) + + @cached_property + def store(self) -> store.StoreResourceWithStreamingResponse: + from .resources.store import StoreResourceWithStreamingResponse + + return StoreResourceWithStreamingResponse(self._client.store) + class AsyncMobilerunWithStreamedResponse: _client: AsyncMobilerun @@ -876,6 +1100,48 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse: return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks) + @cached_property + def agents(self) -> agents.AsyncAgentsResourceWithStreamingResponse: + from .resources.agents import AsyncAgentsResourceWithStreamingResponse + + return AsyncAgentsResourceWithStreamingResponse(self._client.agents) + + @cached_property + def app_events(self) -> app_events.AsyncAppEventsResourceWithStreamingResponse: + from .resources.app_events import AsyncAppEventsResourceWithStreamingResponse + + return AsyncAppEventsResourceWithStreamingResponse(self._client.app_events) + + @cached_property + def notifications(self) -> notifications.AsyncNotificationsResourceWithStreamingResponse: + from .resources.notifications import AsyncNotificationsResourceWithStreamingResponse + + return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications) + + @cached_property + def esims(self) -> esims.AsyncEsimsResourceWithStreamingResponse: + from .resources.esims import AsyncEsimsResourceWithStreamingResponse + + return AsyncEsimsResourceWithStreamingResponse(self._client.esims) + + @cached_property + def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse: + from .resources.messages import AsyncMessagesResourceWithStreamingResponse + + return AsyncMessagesResourceWithStreamingResponse(self._client.messages) + + @cached_property + def numbers(self) -> numbers.AsyncNumbersResourceWithStreamingResponse: + from .resources.numbers import AsyncNumbersResourceWithStreamingResponse + + return AsyncNumbersResourceWithStreamingResponse(self._client.numbers) + + @cached_property + def store(self) -> store.AsyncStoreResourceWithStreamingResponse: + from .resources.store import AsyncStoreResourceWithStreamingResponse + + return AsyncStoreResourceWithStreamingResponse(self._client.store) + Client = Mobilerun diff --git a/src/mobilerun_sdk/resources/__init__.py b/src/mobilerun_sdk/resources/__init__.py index be9be40b..afef0f85 100644 --- a/src/mobilerun_sdk/resources/__init__.py +++ b/src/mobilerun_sdk/resources/__init__.py @@ -8,6 +8,22 @@ AppsResourceWithStreamingResponse, AsyncAppsResourceWithStreamingResponse, ) +from .esims import ( + EsimsResource, + AsyncEsimsResource, + EsimsResourceWithRawResponse, + AsyncEsimsResourceWithRawResponse, + EsimsResourceWithStreamingResponse, + AsyncEsimsResourceWithStreamingResponse, +) +from .store import ( + StoreResource, + AsyncStoreResource, + StoreResourceWithRawResponse, + AsyncStoreResourceWithRawResponse, + StoreResourceWithStreamingResponse, + AsyncStoreResourceWithStreamingResponse, +) from .tasks import ( TasksResource, AsyncTasksResource, @@ -16,6 +32,14 @@ TasksResourceWithStreamingResponse, AsyncTasksResourceWithStreamingResponse, ) +from .agents import ( + AgentsResource, + AsyncAgentsResource, + AgentsResourceWithRawResponse, + AsyncAgentsResourceWithRawResponse, + AgentsResourceWithStreamingResponse, + AsyncAgentsResourceWithStreamingResponse, +) from .models import ( ModelsResource, AsyncModelsResource, @@ -40,6 +64,14 @@ DevicesResourceWithStreamingResponse, AsyncDevicesResourceWithStreamingResponse, ) +from .numbers import ( + NumbersResource, + AsyncNumbersResource, + NumbersResourceWithRawResponse, + AsyncNumbersResourceWithRawResponse, + NumbersResourceWithStreamingResponse, + AsyncNumbersResourceWithStreamingResponse, +) from .proxies import ( ProxiesResource, AsyncProxiesResource, @@ -56,6 +88,14 @@ CarriersResourceWithStreamingResponse, AsyncCarriersResourceWithStreamingResponse, ) +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) from .profiles import ( ProfilesResource, AsyncProfilesResource, @@ -80,6 +120,14 @@ WorkflowsResourceWithStreamingResponse, AsyncWorkflowsResourceWithStreamingResponse, ) +from .app_events import ( + AppEventsResource, + AsyncAppEventsResource, + AppEventsResourceWithRawResponse, + AsyncAppEventsResourceWithRawResponse, + AppEventsResourceWithStreamingResponse, + AsyncAppEventsResourceWithStreamingResponse, +) from .credentials import ( CredentialsResource, AsyncCredentialsResource, @@ -88,6 +136,14 @@ CredentialsResourceWithStreamingResponse, AsyncCredentialsResourceWithStreamingResponse, ) +from .notifications import ( + NotificationsResource, + AsyncNotificationsResource, + NotificationsResourceWithRawResponse, + AsyncNotificationsResourceWithRawResponse, + NotificationsResourceWithStreamingResponse, + AsyncNotificationsResourceWithStreamingResponse, +) __all__ = [ "AppsResource", @@ -156,4 +212,46 @@ "AsyncWebhooksResourceWithRawResponse", "WebhooksResourceWithStreamingResponse", "AsyncWebhooksResourceWithStreamingResponse", + "AgentsResource", + "AsyncAgentsResource", + "AgentsResourceWithRawResponse", + "AsyncAgentsResourceWithRawResponse", + "AgentsResourceWithStreamingResponse", + "AsyncAgentsResourceWithStreamingResponse", + "AppEventsResource", + "AsyncAppEventsResource", + "AppEventsResourceWithRawResponse", + "AsyncAppEventsResourceWithRawResponse", + "AppEventsResourceWithStreamingResponse", + "AsyncAppEventsResourceWithStreamingResponse", + "NotificationsResource", + "AsyncNotificationsResource", + "NotificationsResourceWithRawResponse", + "AsyncNotificationsResourceWithRawResponse", + "NotificationsResourceWithStreamingResponse", + "AsyncNotificationsResourceWithStreamingResponse", + "EsimsResource", + "AsyncEsimsResource", + "EsimsResourceWithRawResponse", + "AsyncEsimsResourceWithRawResponse", + "EsimsResourceWithStreamingResponse", + "AsyncEsimsResourceWithStreamingResponse", + "MessagesResource", + "AsyncMessagesResource", + "MessagesResourceWithRawResponse", + "AsyncMessagesResourceWithRawResponse", + "MessagesResourceWithStreamingResponse", + "AsyncMessagesResourceWithStreamingResponse", + "NumbersResource", + "AsyncNumbersResource", + "NumbersResourceWithRawResponse", + "AsyncNumbersResourceWithRawResponse", + "NumbersResourceWithStreamingResponse", + "AsyncNumbersResourceWithStreamingResponse", + "StoreResource", + "AsyncStoreResource", + "StoreResourceWithRawResponse", + "AsyncStoreResourceWithRawResponse", + "StoreResourceWithStreamingResponse", + "AsyncStoreResourceWithStreamingResponse", ] diff --git a/src/mobilerun_sdk/resources/agents.py b/src/mobilerun_sdk/resources/agents.py new file mode 100644 index 00000000..7d7bb86f --- /dev/null +++ b/src/mobilerun_sdk/resources/agents.py @@ -0,0 +1,135 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .._types import Body, Query, Headers, NotGiven, not_given +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.agent_list_response import AgentListResponse + +__all__ = ["AgentsResource", "AsyncAgentsResource"] + + +class AgentsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> AgentsResourceWithRawResponse: + """ + 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 AgentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AgentsResourceWithStreamingResponse: + """ + 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 AgentsResourceWithStreamingResponse(self) + + def list( + 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, + ) -> AgentListResponse: + """List all available agents with their default configurations.""" + return self._get( + "/agents", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentListResponse, + ) + + +class AsyncAgentsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse: + """ + 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 AsyncAgentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse: + """ + 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 AsyncAgentsResourceWithStreamingResponse(self) + + async def list( + 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, + ) -> AgentListResponse: + """List all available agents with their default configurations.""" + return await self._get( + "/agents", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AgentListResponse, + ) + + +class AgentsResourceWithRawResponse: + def __init__(self, agents: AgentsResource) -> None: + self._agents = agents + + self.list = to_raw_response_wrapper( + agents.list, + ) + + +class AsyncAgentsResourceWithRawResponse: + def __init__(self, agents: AsyncAgentsResource) -> None: + self._agents = agents + + self.list = async_to_raw_response_wrapper( + agents.list, + ) + + +class AgentsResourceWithStreamingResponse: + def __init__(self, agents: AgentsResource) -> None: + self._agents = agents + + self.list = to_streamed_response_wrapper( + agents.list, + ) + + +class AsyncAgentsResourceWithStreamingResponse: + def __init__(self, agents: AsyncAgentsResource) -> None: + self._agents = agents + + self.list = async_to_streamed_response_wrapper( + agents.list, + ) diff --git a/src/mobilerun_sdk/resources/app_events/__init__.py b/src/mobilerun_sdk/resources/app_events/__init__.py new file mode 100644 index 00000000..99d708c8 --- /dev/null +++ b/src/mobilerun_sdk/resources/app_events/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .catalog import ( + CatalogResource, + AsyncCatalogResource, + CatalogResourceWithRawResponse, + AsyncCatalogResourceWithRawResponse, + CatalogResourceWithStreamingResponse, + AsyncCatalogResourceWithStreamingResponse, +) +from .app_events import ( + AppEventsResource, + AsyncAppEventsResource, + AppEventsResourceWithRawResponse, + AsyncAppEventsResourceWithRawResponse, + AppEventsResourceWithStreamingResponse, + AsyncAppEventsResourceWithStreamingResponse, +) + +__all__ = [ + "CatalogResource", + "AsyncCatalogResource", + "CatalogResourceWithRawResponse", + "AsyncCatalogResourceWithRawResponse", + "CatalogResourceWithStreamingResponse", + "AsyncCatalogResourceWithStreamingResponse", + "AppEventsResource", + "AsyncAppEventsResource", + "AppEventsResourceWithRawResponse", + "AsyncAppEventsResourceWithRawResponse", + "AppEventsResourceWithStreamingResponse", + "AsyncAppEventsResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/app_events/app_events.py b/src/mobilerun_sdk/resources/app_events/app_events.py new file mode 100644 index 00000000..85c4260b --- /dev/null +++ b/src/mobilerun_sdk/resources/app_events/app_events.py @@ -0,0 +1,325 @@ +# 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 ...types import app_event_list_params +from .catalog import ( + CatalogResource, + AsyncCatalogResource, + CatalogResourceWithRawResponse, + AsyncCatalogResourceWithRawResponse, + CatalogResourceWithStreamingResponse, + AsyncCatalogResourceWithStreamingResponse, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.app_event_list_response import AppEventListResponse +from ...types.app_event_retrieve_response import AppEventRetrieveResponse + +__all__ = ["AppEventsResource", "AsyncAppEventsResource"] + + +class AppEventsResource(SyncAPIResource): + @cached_property + def catalog(self) -> CatalogResource: + return CatalogResource(self._client) + + @cached_property + def with_raw_response(self) -> AppEventsResourceWithRawResponse: + """ + 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 AppEventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AppEventsResourceWithStreamingResponse: + """ + 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 AppEventsResourceWithStreamingResponse(self) + + def retrieve( + self, + 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, + ) -> AppEventRetrieveResponse: + """ + Fetch a single structured app event by its ID, including its typed payload, + source, and originating device. Returns 404 if no event matches. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/app-events/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppEventRetrieveResponse, + ) + + def list( + self, + *, + device_id: str | Omit = omit, + event_type: str | Omit = omit, + from_: Optional[str] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + source: Literal["app", "system", "device", "webhook"] | Omit = omit, + to: Optional[str] | 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, + ) -> AppEventListResponse: + """Structured, app-scoped events (e.g. + + app.whatsapp.message_received) derived from + raw device notifications. Typed columns — not raw payloads (those stay in the + event log). + + 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( + "/app-events", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "device_id": device_id, + "event_type": event_type, + "from_": from_, + "page": page, + "page_size": page_size, + "source": source, + "to": to, + }, + app_event_list_params.AppEventListParams, + ), + ), + cast_to=AppEventListResponse, + ) + + +class AsyncAppEventsResource(AsyncAPIResource): + @cached_property + def catalog(self) -> AsyncCatalogResource: + return AsyncCatalogResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncAppEventsResourceWithRawResponse: + """ + 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 AsyncAppEventsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncAppEventsResourceWithStreamingResponse: + """ + 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 AsyncAppEventsResourceWithStreamingResponse(self) + + async def retrieve( + self, + 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, + ) -> AppEventRetrieveResponse: + """ + Fetch a single structured app event by its ID, including its typed payload, + source, and originating device. Returns 404 if no event matches. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/app-events/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppEventRetrieveResponse, + ) + + async def list( + self, + *, + device_id: str | Omit = omit, + event_type: str | Omit = omit, + from_: Optional[str] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + source: Literal["app", "system", "device", "webhook"] | Omit = omit, + to: Optional[str] | 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, + ) -> AppEventListResponse: + """Structured, app-scoped events (e.g. + + app.whatsapp.message_received) derived from + raw device notifications. Typed columns — not raw payloads (those stay in the + event log). + + 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( + "/app-events", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "device_id": device_id, + "event_type": event_type, + "from_": from_, + "page": page, + "page_size": page_size, + "source": source, + "to": to, + }, + app_event_list_params.AppEventListParams, + ), + ), + cast_to=AppEventListResponse, + ) + + +class AppEventsResourceWithRawResponse: + def __init__(self, app_events: AppEventsResource) -> None: + self._app_events = app_events + + self.retrieve = to_raw_response_wrapper( + app_events.retrieve, + ) + self.list = to_raw_response_wrapper( + app_events.list, + ) + + @cached_property + def catalog(self) -> CatalogResourceWithRawResponse: + return CatalogResourceWithRawResponse(self._app_events.catalog) + + +class AsyncAppEventsResourceWithRawResponse: + def __init__(self, app_events: AsyncAppEventsResource) -> None: + self._app_events = app_events + + self.retrieve = async_to_raw_response_wrapper( + app_events.retrieve, + ) + self.list = async_to_raw_response_wrapper( + app_events.list, + ) + + @cached_property + def catalog(self) -> AsyncCatalogResourceWithRawResponse: + return AsyncCatalogResourceWithRawResponse(self._app_events.catalog) + + +class AppEventsResourceWithStreamingResponse: + def __init__(self, app_events: AppEventsResource) -> None: + self._app_events = app_events + + self.retrieve = to_streamed_response_wrapper( + app_events.retrieve, + ) + self.list = to_streamed_response_wrapper( + app_events.list, + ) + + @cached_property + def catalog(self) -> CatalogResourceWithStreamingResponse: + return CatalogResourceWithStreamingResponse(self._app_events.catalog) + + +class AsyncAppEventsResourceWithStreamingResponse: + def __init__(self, app_events: AsyncAppEventsResource) -> None: + self._app_events = app_events + + self.retrieve = async_to_streamed_response_wrapper( + app_events.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + app_events.list, + ) + + @cached_property + def catalog(self) -> AsyncCatalogResourceWithStreamingResponse: + return AsyncCatalogResourceWithStreamingResponse(self._app_events.catalog) diff --git a/src/mobilerun_sdk/resources/app_events/catalog.py b/src/mobilerun_sdk/resources/app_events/catalog.py new file mode 100644 index 00000000..cddabc05 --- /dev/null +++ b/src/mobilerun_sdk/resources/app_events/catalog.py @@ -0,0 +1,227 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import path_template +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.app_events.catalog_list_response import CatalogListResponse +from ...types.app_events.catalog_retrieve_response import CatalogRetrieveResponse + +__all__ = ["CatalogResource", "AsyncCatalogResource"] + + +class CatalogResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> CatalogResourceWithRawResponse: + """ + 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 CatalogResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> CatalogResourceWithStreamingResponse: + """ + 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 CatalogResourceWithStreamingResponse(self) + + def retrieve( + self, + app_event_type: 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, + ) -> CatalogRetrieveResponse: + """ + Fetch a single selectable app event by its appEventType (e.g. + app.whatsapp.message_received). + + 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 app_event_type: + raise ValueError(f"Expected a non-empty value for `app_event_type` but received {app_event_type!r}") + return self._get( + path_template("/app-events/catalog/{app_event_type}", app_event_type=app_event_type), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CatalogRetrieveResponse, + ) + + def list( + 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, + ) -> CatalogListResponse: + """Selectable app-based trigger events (e.g. + + app.whatsapp.message_received) with + their predefined payload — served from the JSON definition registry (always in + sync, no DB). + """ + return self._get( + "/app-events/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CatalogListResponse, + ) + + +class AsyncCatalogResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncCatalogResourceWithRawResponse: + """ + 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 AsyncCatalogResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncCatalogResourceWithStreamingResponse: + """ + 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 AsyncCatalogResourceWithStreamingResponse(self) + + async def retrieve( + self, + app_event_type: 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, + ) -> CatalogRetrieveResponse: + """ + Fetch a single selectable app event by its appEventType (e.g. + app.whatsapp.message_received). + + 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 app_event_type: + raise ValueError(f"Expected a non-empty value for `app_event_type` but received {app_event_type!r}") + return await self._get( + path_template("/app-events/catalog/{app_event_type}", app_event_type=app_event_type), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CatalogRetrieveResponse, + ) + + async def list( + 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, + ) -> CatalogListResponse: + """Selectable app-based trigger events (e.g. + + app.whatsapp.message_received) with + their predefined payload — served from the JSON definition registry (always in + sync, no DB). + """ + return await self._get( + "/app-events/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=CatalogListResponse, + ) + + +class CatalogResourceWithRawResponse: + def __init__(self, catalog: CatalogResource) -> None: + self._catalog = catalog + + self.retrieve = to_raw_response_wrapper( + catalog.retrieve, + ) + self.list = to_raw_response_wrapper( + catalog.list, + ) + + +class AsyncCatalogResourceWithRawResponse: + def __init__(self, catalog: AsyncCatalogResource) -> None: + self._catalog = catalog + + self.retrieve = async_to_raw_response_wrapper( + catalog.retrieve, + ) + self.list = async_to_raw_response_wrapper( + catalog.list, + ) + + +class CatalogResourceWithStreamingResponse: + def __init__(self, catalog: CatalogResource) -> None: + self._catalog = catalog + + self.retrieve = to_streamed_response_wrapper( + catalog.retrieve, + ) + self.list = to_streamed_response_wrapper( + catalog.list, + ) + + +class AsyncCatalogResourceWithStreamingResponse: + def __init__(self, catalog: AsyncCatalogResource) -> None: + self._catalog = catalog + + self.retrieve = async_to_streamed_response_wrapper( + catalog.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + catalog.list, + ) diff --git a/src/mobilerun_sdk/resources/apps.py b/src/mobilerun_sdk/resources/apps.py index 7a9699a9..e46dbbf0 100644 --- a/src/mobilerun_sdk/resources/apps.py +++ b/src/mobilerun_sdk/resources/apps.py @@ -24,6 +24,7 @@ from ..types.app_retrieve_response import AppRetrieveResponse from ..types.app_mark_failed_response import AppMarkFailedResponse from ..types.app_list_versions_response import AppListVersionsResponse +from ..types.app_storage_usage_response import AppStorageUsageResponse from ..types.app_confirm_upload_response import AppConfirmUploadResponse from ..types.app_create_signed_upload_url_response import AppCreateSignedUploadURLResponse @@ -330,6 +331,28 @@ def mark_failed( cast_to=AppMarkFailedResponse, ) + def storage_usage( + 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, + ) -> AppStorageUsageResponse: + """ + Returns the user’s total storage quota, bytes used, and remaining bytes — the + reliable maximum size for the next upload. + """ + return self._get( + "/apps/storage-usage", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppStorageUsageResponse, + ) + class AsyncAppsResource(AsyncAPIResource): @cached_property @@ -631,6 +654,28 @@ async def mark_failed( cast_to=AppMarkFailedResponse, ) + async def storage_usage( + 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, + ) -> AppStorageUsageResponse: + """ + Returns the user’s total storage quota, bytes used, and remaining bytes — the + reliable maximum size for the next upload. + """ + return await self._get( + "/apps/storage-usage", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppStorageUsageResponse, + ) + class AppsResourceWithRawResponse: def __init__(self, apps: AppsResource) -> None: @@ -657,6 +702,9 @@ def __init__(self, apps: AppsResource) -> None: self.mark_failed = to_raw_response_wrapper( apps.mark_failed, ) + self.storage_usage = to_raw_response_wrapper( + apps.storage_usage, + ) class AsyncAppsResourceWithRawResponse: @@ -684,6 +732,9 @@ def __init__(self, apps: AsyncAppsResource) -> None: self.mark_failed = async_to_raw_response_wrapper( apps.mark_failed, ) + self.storage_usage = async_to_raw_response_wrapper( + apps.storage_usage, + ) class AppsResourceWithStreamingResponse: @@ -711,6 +762,9 @@ def __init__(self, apps: AppsResource) -> None: self.mark_failed = to_streamed_response_wrapper( apps.mark_failed, ) + self.storage_usage = to_streamed_response_wrapper( + apps.storage_usage, + ) class AsyncAppsResourceWithStreamingResponse: @@ -738,3 +792,6 @@ def __init__(self, apps: AsyncAppsResource) -> None: self.mark_failed = async_to_streamed_response_wrapper( apps.mark_failed, ) + self.storage_usage = async_to_streamed_response_wrapper( + apps.storage_usage, + ) diff --git a/src/mobilerun_sdk/resources/credentials/packages/packages.py b/src/mobilerun_sdk/resources/credentials/packages/packages.py index d82ed0eb..ba676828 100644 --- a/src/mobilerun_sdk/resources/credentials/packages/packages.py +++ b/src/mobilerun_sdk/resources/credentials/packages/packages.py @@ -26,6 +26,7 @@ ) from ....types.credentials.package_list_response import PackageListResponse from ....types.credentials.package_create_response import PackageCreateResponse +from ....types.credentials.package_list_all_response import PackageListAllResponse __all__ = ["PackagesResource", "AsyncPackagesResource"] @@ -123,6 +124,29 @@ def list( cast_to=PackageListResponse, ) + def list_all( + 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, + ) -> PackageListAllResponse: + """ + Returns the names of all packages (apps) the authenticated owner has credentials + grouped under. Use this to discover which `packageName` values are valid for the + per-package credential routes. + """ + return self._get( + "/credentials/packages", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PackageListAllResponse, + ) + class AsyncPackagesResource(AsyncAPIResource): @cached_property @@ -217,6 +241,29 @@ async def list( cast_to=PackageListResponse, ) + async def list_all( + 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, + ) -> PackageListAllResponse: + """ + Returns the names of all packages (apps) the authenticated owner has credentials + grouped under. Use this to discover which `packageName` values are valid for the + per-package credential routes. + """ + return await self._get( + "/credentials/packages", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=PackageListAllResponse, + ) + class PackagesResourceWithRawResponse: def __init__(self, packages: PackagesResource) -> None: @@ -228,6 +275,9 @@ def __init__(self, packages: PackagesResource) -> None: self.list = to_raw_response_wrapper( packages.list, ) + self.list_all = to_raw_response_wrapper( + packages.list_all, + ) @cached_property def credentials(self) -> CredentialsResourceWithRawResponse: @@ -244,6 +294,9 @@ def __init__(self, packages: AsyncPackagesResource) -> None: self.list = async_to_raw_response_wrapper( packages.list, ) + self.list_all = async_to_raw_response_wrapper( + packages.list_all, + ) @cached_property def credentials(self) -> AsyncCredentialsResourceWithRawResponse: @@ -260,6 +313,9 @@ def __init__(self, packages: PackagesResource) -> None: self.list = to_streamed_response_wrapper( packages.list, ) + self.list_all = to_streamed_response_wrapper( + packages.list_all, + ) @cached_property def credentials(self) -> CredentialsResourceWithStreamingResponse: @@ -276,6 +332,9 @@ def __init__(self, packages: AsyncPackagesResource) -> None: self.list = async_to_streamed_response_wrapper( packages.list, ) + self.list_all = async_to_streamed_response_wrapper( + packages.list_all, + ) @cached_property def credentials(self) -> AsyncCredentialsResourceWithStreamingResponse: diff --git a/src/mobilerun_sdk/resources/devices/__init__.py b/src/mobilerun_sdk/resources/devices/__init__.py index 77ef45e2..4f1a6d2b 100644 --- a/src/mobilerun_sdk/resources/devices/__init__.py +++ b/src/mobilerun_sdk/resources/devices/__init__.py @@ -24,6 +24,14 @@ FilesResourceWithStreamingResponse, AsyncFilesResourceWithStreamingResponse, ) +from .kiosk import ( + KioskResource, + AsyncKioskResource, + KioskResourceWithRawResponse, + AsyncKioskResourceWithRawResponse, + KioskResourceWithStreamingResponse, + AsyncKioskResourceWithStreamingResponse, +) from .proxy import ( ProxyResource, AsyncProxyResource, @@ -56,6 +64,14 @@ ActionsResourceWithStreamingResponse, AsyncActionsResourceWithStreamingResponse, ) +from .browser import ( + BrowserResource, + AsyncBrowserResource, + BrowserResourceWithRawResponse, + AsyncBrowserResourceWithRawResponse, + BrowserResourceWithStreamingResponse, + AsyncBrowserResourceWithStreamingResponse, +) from .devices import ( DevicesResource, AsyncDevicesResource, @@ -112,6 +128,30 @@ TimezoneResourceWithStreamingResponse, AsyncTimezoneResourceWithStreamingResponse, ) +from .deep_link import ( + DeepLinkResource, + AsyncDeepLinkResource, + DeepLinkResourceWithRawResponse, + AsyncDeepLinkResourceWithRawResponse, + DeepLinkResourceWithStreamingResponse, + AsyncDeepLinkResourceWithStreamingResponse, +) +from .recordings import ( + RecordingsResource, + AsyncRecordingsResource, + RecordingsResourceWithRawResponse, + AsyncRecordingsResourceWithRawResponse, + RecordingsResourceWithStreamingResponse, + AsyncRecordingsResourceWithStreamingResponse, +) +from .media_sessions import ( + MediaSessionsResource, + AsyncMediaSessionsResource, + MediaSessionsResourceWithRawResponse, + AsyncMediaSessionsResourceWithRawResponse, + MediaSessionsResourceWithStreamingResponse, + AsyncMediaSessionsResourceWithStreamingResponse, +) __all__ = [ "ActionsResource", @@ -192,6 +232,36 @@ "AsyncLanguageResourceWithRawResponse", "LanguageResourceWithStreamingResponse", "AsyncLanguageResourceWithStreamingResponse", + "DeepLinkResource", + "AsyncDeepLinkResource", + "DeepLinkResourceWithRawResponse", + "AsyncDeepLinkResourceWithRawResponse", + "DeepLinkResourceWithStreamingResponse", + "AsyncDeepLinkResourceWithStreamingResponse", + "BrowserResource", + "AsyncBrowserResource", + "BrowserResourceWithRawResponse", + "AsyncBrowserResourceWithRawResponse", + "BrowserResourceWithStreamingResponse", + "AsyncBrowserResourceWithStreamingResponse", + "KioskResource", + "AsyncKioskResource", + "KioskResourceWithRawResponse", + "AsyncKioskResourceWithRawResponse", + "KioskResourceWithStreamingResponse", + "AsyncKioskResourceWithStreamingResponse", + "MediaSessionsResource", + "AsyncMediaSessionsResource", + "MediaSessionsResourceWithRawResponse", + "AsyncMediaSessionsResourceWithRawResponse", + "MediaSessionsResourceWithStreamingResponse", + "AsyncMediaSessionsResourceWithStreamingResponse", + "RecordingsResource", + "AsyncRecordingsResource", + "RecordingsResourceWithRawResponse", + "AsyncRecordingsResourceWithRawResponse", + "RecordingsResourceWithStreamingResponse", + "AsyncRecordingsResourceWithStreamingResponse", "DevicesResource", "AsyncDevicesResource", "DevicesResourceWithRawResponse", diff --git a/src/mobilerun_sdk/resources/devices/apps.py b/src/mobilerun_sdk/resources/devices/apps.py index bec1e690..f89729c8 100644 --- a/src/mobilerun_sdk/resources/devices/apps.py +++ b/src/mobilerun_sdk/resources/devices/apps.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import overload +from typing_extensions import Literal, overload import httpx @@ -20,6 +20,7 @@ from ..._base_client import make_request_options from ...types.devices import app_list_params, app_stop_params, app_start_params, app_install_params from ...types.devices.app_list_response import AppListResponse +from ...types.devices.app_list_installs_response import AppListInstallsResponse __all__ = ["AppsResource", "AsyncAppsResource"] @@ -143,6 +144,62 @@ def delete( cast_to=NoneType, ) + def grant_permission( + self, + permission: Literal["POST_NOTIFICATIONS"], + *, + 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: + """Grants an Android runtime permission to the package named in the path. + + The + permission is given by its short name (e.g. POST_NOTIFICATIONS). + + Args: + permission: Android runtime permission, short name (e.g. POST_NOTIFICATIONS). + + 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}") + if not permission: + raise ValueError(f"Expected a non-empty value for `permission` but received {permission!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( + path_template( + "/devices/{device_id}/apps/{package_name}/permissions/{permission}", + device_id=device_id, + package_name=package_name, + permission=permission, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + @overload def install( self, @@ -280,6 +337,106 @@ def install( cast_to=NoneType, ) + def list_installs( + 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, + ) -> AppListInstallsResponse: + """ + Reports the backend's view of background app-install attempts on this device — + status reflects the install ATTEMPT, not device ground truth; list-apps remains + authoritative for what is actually installed. Records are in-memory and lost on + service restart; terminal records are kept ~15 minutes. Not gated on device + readiness, so it also answers while the device is offline or crashed. + + 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( + path_template("/devices/{device_id}/apps/installs", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppListInstallsResponse, + ) + + def revoke_permission( + self, + permission: Literal["POST_NOTIFICATIONS"], + *, + 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: + """Revokes an Android runtime permission from the package named in the path. + + The + permission is given by its short name (e.g. POST_NOTIFICATIONS). + + Args: + permission: Android runtime permission, short name (e.g. POST_NOTIFICATIONS). + + 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}") + if not permission: + raise ValueError(f"Expected a non-empty value for `permission` but received {permission!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( + path_template( + "/devices/{device_id}/apps/{package_name}/permissions/{permission}", + device_id=device_id, + package_name=package_name, + permission=permission, + ), + 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, @@ -499,6 +656,62 @@ async def delete( cast_to=NoneType, ) + async def grant_permission( + self, + permission: Literal["POST_NOTIFICATIONS"], + *, + 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: + """Grants an Android runtime permission to the package named in the path. + + The + permission is given by its short name (e.g. POST_NOTIFICATIONS). + + Args: + permission: Android runtime permission, short name (e.g. POST_NOTIFICATIONS). + + 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}") + if not permission: + raise ValueError(f"Expected a non-empty value for `permission` but received {permission!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( + path_template( + "/devices/{device_id}/apps/{package_name}/permissions/{permission}", + device_id=device_id, + package_name=package_name, + permission=permission, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + @overload async def install( self, @@ -636,6 +849,106 @@ async def install( cast_to=NoneType, ) + async def list_installs( + 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, + ) -> AppListInstallsResponse: + """ + Reports the backend's view of background app-install attempts on this device — + status reflects the install ATTEMPT, not device ground truth; list-apps remains + authoritative for what is actually installed. Records are in-memory and lost on + service restart; terminal records are kept ~15 minutes. Not gated on device + readiness, so it also answers while the device is offline or crashed. + + 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( + path_template("/devices/{device_id}/apps/installs", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppListInstallsResponse, + ) + + async def revoke_permission( + self, + permission: Literal["POST_NOTIFICATIONS"], + *, + 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: + """Revokes an Android runtime permission from the package named in the path. + + The + permission is given by its short name (e.g. POST_NOTIFICATIONS). + + Args: + permission: Android runtime permission, short name (e.g. POST_NOTIFICATIONS). + + 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}") + if not permission: + raise ValueError(f"Expected a non-empty value for `permission` but received {permission!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( + path_template( + "/devices/{device_id}/apps/{package_name}/permissions/{permission}", + device_id=device_id, + package_name=package_name, + permission=permission, + ), + 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, @@ -746,9 +1059,18 @@ def __init__(self, apps: AppsResource) -> None: self.delete = to_raw_response_wrapper( apps.delete, ) + self.grant_permission = to_raw_response_wrapper( + apps.grant_permission, + ) self.install = to_raw_response_wrapper( apps.install, ) + self.list_installs = to_raw_response_wrapper( + apps.list_installs, + ) + self.revoke_permission = to_raw_response_wrapper( + apps.revoke_permission, + ) self.start = to_raw_response_wrapper( apps.start, ) @@ -767,9 +1089,18 @@ def __init__(self, apps: AsyncAppsResource) -> None: self.delete = async_to_raw_response_wrapper( apps.delete, ) + self.grant_permission = async_to_raw_response_wrapper( + apps.grant_permission, + ) self.install = async_to_raw_response_wrapper( apps.install, ) + self.list_installs = async_to_raw_response_wrapper( + apps.list_installs, + ) + self.revoke_permission = async_to_raw_response_wrapper( + apps.revoke_permission, + ) self.start = async_to_raw_response_wrapper( apps.start, ) @@ -788,9 +1119,18 @@ def __init__(self, apps: AppsResource) -> None: self.delete = to_streamed_response_wrapper( apps.delete, ) + self.grant_permission = to_streamed_response_wrapper( + apps.grant_permission, + ) self.install = to_streamed_response_wrapper( apps.install, ) + self.list_installs = to_streamed_response_wrapper( + apps.list_installs, + ) + self.revoke_permission = to_streamed_response_wrapper( + apps.revoke_permission, + ) self.start = to_streamed_response_wrapper( apps.start, ) @@ -809,9 +1149,18 @@ def __init__(self, apps: AsyncAppsResource) -> None: self.delete = async_to_streamed_response_wrapper( apps.delete, ) + self.grant_permission = async_to_streamed_response_wrapper( + apps.grant_permission, + ) self.install = async_to_streamed_response_wrapper( apps.install, ) + self.list_installs = async_to_streamed_response_wrapper( + apps.list_installs, + ) + self.revoke_permission = async_to_streamed_response_wrapper( + apps.revoke_permission, + ) self.start = async_to_streamed_response_wrapper( apps.start, ) diff --git a/src/mobilerun_sdk/resources/devices/browser.py b/src/mobilerun_sdk/resources/devices/browser.py new file mode 100644 index 00000000..42eca5bb --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/browser.py @@ -0,0 +1,199 @@ +# 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, path_template, 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 browser_execute_script_params +from ...types.devices.browser_execute_script_response import BrowserExecuteScriptResponse + +__all__ = ["BrowserResource", "AsyncBrowserResource"] + + +class BrowserResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BrowserResourceWithRawResponse: + """ + 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 BrowserResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BrowserResourceWithStreamingResponse: + """ + 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 BrowserResourceWithStreamingResponse(self) + + def execute_script( + self, + device_id: str, + *, + script: 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, + ) -> BrowserExecuteScriptResponse: + """ + Evaluates a JavaScript expression in the device's foreground Chrome tab via the + Chrome DevTools Protocol and returns its JSON-serialized result. Devices without + browser support return an unsupported-feature error. + + Args: + script: JavaScript expression to evaluate in the device's foreground Chrome tab (CDP + Runtime.evaluate). It is an expression, not a function body — the expression's + value is returned (no top-level 'return'). Must evaluate to a JSON-serializable + value; wrap multi-statement logic in an IIFE, e.g. (() => { ... ; return x })(). + + 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._post( + path_template("/devices/{device_id}/browser/execute-script", device_id=device_id), + body=maybe_transform({"script": script}, browser_execute_script_params.BrowserExecuteScriptParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserExecuteScriptResponse, + ) + + +class AsyncBrowserResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBrowserResourceWithRawResponse: + """ + 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 AsyncBrowserResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBrowserResourceWithStreamingResponse: + """ + 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 AsyncBrowserResourceWithStreamingResponse(self) + + async def execute_script( + self, + device_id: str, + *, + script: 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, + ) -> BrowserExecuteScriptResponse: + """ + Evaluates a JavaScript expression in the device's foreground Chrome tab via the + Chrome DevTools Protocol and returns its JSON-serialized result. Devices without + browser support return an unsupported-feature error. + + Args: + script: JavaScript expression to evaluate in the device's foreground Chrome tab (CDP + Runtime.evaluate). It is an expression, not a function body — the expression's + value is returned (no top-level 'return'). Must evaluate to a JSON-serializable + value; wrap multi-statement logic in an IIFE, e.g. (() => { ... ; return x })(). + + 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._post( + path_template("/devices/{device_id}/browser/execute-script", device_id=device_id), + body=await async_maybe_transform( + {"script": script}, browser_execute_script_params.BrowserExecuteScriptParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=BrowserExecuteScriptResponse, + ) + + +class BrowserResourceWithRawResponse: + def __init__(self, browser: BrowserResource) -> None: + self._browser = browser + + self.execute_script = to_raw_response_wrapper( + browser.execute_script, + ) + + +class AsyncBrowserResourceWithRawResponse: + def __init__(self, browser: AsyncBrowserResource) -> None: + self._browser = browser + + self.execute_script = async_to_raw_response_wrapper( + browser.execute_script, + ) + + +class BrowserResourceWithStreamingResponse: + def __init__(self, browser: BrowserResource) -> None: + self._browser = browser + + self.execute_script = to_streamed_response_wrapper( + browser.execute_script, + ) + + +class AsyncBrowserResourceWithStreamingResponse: + def __init__(self, browser: AsyncBrowserResource) -> None: + self._browser = browser + + self.execute_script = async_to_streamed_response_wrapper( + browser.execute_script, + ) diff --git a/src/mobilerun_sdk/resources/devices/deep_link.py b/src/mobilerun_sdk/resources/devices/deep_link.py new file mode 100644 index 00000000..ceee3bb9 --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/deep_link.py @@ -0,0 +1,232 @@ +# 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, path_template, 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 deep_link_execute_deep_link_params + +__all__ = ["DeepLinkResource", "AsyncDeepLinkResource"] + + +class DeepLinkResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> DeepLinkResourceWithRawResponse: + """ + 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 DeepLinkResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> DeepLinkResourceWithStreamingResponse: + """ + 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 DeepLinkResourceWithStreamingResponse(self) + + def execute_deep_link( + self, + device_id: str, + *, + deep_link: str, + action: str | Omit = omit, + bundle_id: str | Omit = omit, + package_name: 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: + """Opens a deep link on the device. + + On Android the link is dispatched as an intent + — packageName optionally pins it to a specific app and action overrides the + default android.intent.action.VIEW. On iOS the URL is opened directly and the + optional fields must be omitted. Protected packages are rejected. + + Args: + deep_link: Deep link to open (e.g. myapp://path or https://example.com/path) + + action: Android only: intent action to dispatch. Defaults to android.intent.action.VIEW. + + bundle_id: Reserved for targeting a specific iOS app; currently rejected as unsupported. + + package_name: Android only: package to receive the intent (e.g. com.example.app). Omit to let + the system pick the handler. + + 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( + path_template("/devices/{device_id}/apps/open-deep-link", device_id=device_id), + body=maybe_transform( + { + "deep_link": deep_link, + "action": action, + "bundle_id": bundle_id, + "package_name": package_name, + }, + deep_link_execute_deep_link_params.DeepLinkExecuteDeepLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncDeepLinkResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncDeepLinkResourceWithRawResponse: + """ + 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 AsyncDeepLinkResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncDeepLinkResourceWithStreamingResponse: + """ + 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 AsyncDeepLinkResourceWithStreamingResponse(self) + + async def execute_deep_link( + self, + device_id: str, + *, + deep_link: str, + action: str | Omit = omit, + bundle_id: str | Omit = omit, + package_name: 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: + """Opens a deep link on the device. + + On Android the link is dispatched as an intent + — packageName optionally pins it to a specific app and action overrides the + default android.intent.action.VIEW. On iOS the URL is opened directly and the + optional fields must be omitted. Protected packages are rejected. + + Args: + deep_link: Deep link to open (e.g. myapp://path or https://example.com/path) + + action: Android only: intent action to dispatch. Defaults to android.intent.action.VIEW. + + bundle_id: Reserved for targeting a specific iOS app; currently rejected as unsupported. + + package_name: Android only: package to receive the intent (e.g. com.example.app). Omit to let + the system pick the handler. + + 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( + path_template("/devices/{device_id}/apps/open-deep-link", device_id=device_id), + body=await async_maybe_transform( + { + "deep_link": deep_link, + "action": action, + "bundle_id": bundle_id, + "package_name": package_name, + }, + deep_link_execute_deep_link_params.DeepLinkExecuteDeepLinkParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class DeepLinkResourceWithRawResponse: + def __init__(self, deep_link: DeepLinkResource) -> None: + self._deep_link = deep_link + + self.execute_deep_link = to_raw_response_wrapper( + deep_link.execute_deep_link, + ) + + +class AsyncDeepLinkResourceWithRawResponse: + def __init__(self, deep_link: AsyncDeepLinkResource) -> None: + self._deep_link = deep_link + + self.execute_deep_link = async_to_raw_response_wrapper( + deep_link.execute_deep_link, + ) + + +class DeepLinkResourceWithStreamingResponse: + def __init__(self, deep_link: DeepLinkResource) -> None: + self._deep_link = deep_link + + self.execute_deep_link = to_streamed_response_wrapper( + deep_link.execute_deep_link, + ) + + +class AsyncDeepLinkResourceWithStreamingResponse: + def __init__(self, deep_link: AsyncDeepLinkResource) -> None: + self._deep_link = deep_link + + self.execute_deep_link = async_to_streamed_response_wrapper( + deep_link.execute_deep_link, + ) diff --git a/src/mobilerun_sdk/resources/devices/devices.py b/src/mobilerun_sdk/resources/devices/devices.py index c466e2fe..b3cfb65a 100644 --- a/src/mobilerun_sdk/resources/devices/devices.py +++ b/src/mobilerun_sdk/resources/devices/devices.py @@ -16,14 +16,6 @@ AppsResourceWithStreamingResponse, AsyncAppsResourceWithStreamingResponse, ) -from .esim import ( - EsimResource, - AsyncEsimResource, - EsimResourceWithRawResponse, - AsyncEsimResourceWithRawResponse, - EsimResourceWithStreamingResponse, - AsyncEsimResourceWithStreamingResponse, -) from .files import ( FilesResource, AsyncFilesResource, @@ -32,6 +24,14 @@ FilesResourceWithStreamingResponse, AsyncFilesResourceWithStreamingResponse, ) +from .kiosk import ( + KioskResource, + AsyncKioskResource, + KioskResourceWithRawResponse, + AsyncKioskResourceWithRawResponse, + KioskResourceWithStreamingResponse, + AsyncKioskResourceWithStreamingResponse, +) from .proxy import ( ProxyResource, AsyncProxyResource, @@ -65,6 +65,14 @@ ActionsResourceWithStreamingResponse, AsyncActionsResourceWithStreamingResponse, ) +from .browser import ( + BrowserResource, + AsyncBrowserResource, + BrowserResourceWithRawResponse, + AsyncBrowserResourceWithRawResponse, + BrowserResourceWithStreamingResponse, + AsyncBrowserResourceWithStreamingResponse, +) from .profile import ( ProfileResource, AsyncProfileResource, @@ -116,6 +124,30 @@ AsyncTimezoneResourceWithStreamingResponse, ) from ..._compat import cached_property +from .deep_link import ( + DeepLinkResource, + AsyncDeepLinkResource, + DeepLinkResourceWithRawResponse, + AsyncDeepLinkResourceWithRawResponse, + DeepLinkResourceWithStreamingResponse, + AsyncDeepLinkResourceWithStreamingResponse, +) +from .esim.esim import ( + EsimResource, + AsyncEsimResource, + EsimResourceWithRawResponse, + AsyncEsimResourceWithRawResponse, + EsimResourceWithStreamingResponse, + AsyncEsimResourceWithStreamingResponse, +) +from .recordings import ( + RecordingsResource, + AsyncRecordingsResource, + RecordingsResourceWithRawResponse, + AsyncRecordingsResourceWithRawResponse, + RecordingsResourceWithStreamingResponse, + AsyncRecordingsResourceWithStreamingResponse, +) from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( to_raw_response_wrapper, @@ -124,13 +156,25 @@ async_to_streamed_response_wrapper, ) from ..._base_client import make_request_options -from ...types.device import Device +from .media_sessions import ( + MediaSessionsResource, + AsyncMediaSessionsResource, + MediaSessionsResourceWithRawResponse, + AsyncMediaSessionsResourceWithRawResponse, + MediaSessionsResourceWithStreamingResponse, + AsyncMediaSessionsResourceWithStreamingResponse, +) from ...types.device_list_response import DeviceListResponse from ...types.device_count_response import DeviceCountResponse +from ...types.device_create_response import DeviceCreateResponse from ...types.shared_params.location import Location +from ...types.device_retrieve_response import DeviceRetrieveResponse +from ...types.device_set_name_response import DeviceSetNameResponse +from ...types.device_wait_ready_response import DeviceWaitReadyResponse from ...types.device_fingerprint_response import DeviceFingerprintResponse from ...types.shared_params.device_carrier import DeviceCarrier from ...types.shared_params.device_identifiers import DeviceIdentifiers +from ...types.device_retrieve_capabilities_response import DeviceRetrieveCapabilitiesResponse __all__ = ["DevicesResource", "AsyncDevicesResource"] @@ -188,6 +232,26 @@ def timezone(self) -> TimezoneResource: def language(self) -> LanguageResource: return LanguageResource(self._client) + @cached_property + def deep_link(self) -> DeepLinkResource: + return DeepLinkResource(self._client) + + @cached_property + def browser(self) -> BrowserResource: + return BrowserResource(self._client) + + @cached_property + def kiosk(self) -> KioskResource: + return KioskResource(self._client) + + @cached_property + def media_sessions(self) -> MediaSessionsResource: + return MediaSessionsResource(self._client) + + @cached_property + def recordings(self) -> RecordingsResource: + return RecordingsResource(self._client) + @cached_property def with_raw_response(self) -> DevicesResourceWithRawResponse: """ @@ -238,7 +302,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceCreateResponse: """ Requests a new device for the authenticated user from the device spec in the request body. Optional query parameters select the canonical device type, target @@ -304,7 +368,7 @@ def create( device_create_params.DeviceCreateParams, ), ), - cast_to=Device, + cast_to=DeviceCreateResponse, ) def retrieve( @@ -317,7 +381,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceRetrieveResponse: """ Returns the current state and metadata for a single device, including its lifecycle state, type, stream URL, billing strategy, and timestamps. A stream @@ -339,7 +403,7 @@ def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceRetrieveResponse, ) def list( @@ -569,6 +633,81 @@ def reset( cast_to=NoneType, ) + def resume( + 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: + """ + Wakes a parked device: capacity is preflighted (the device's data may be + replicated to another node if its home is full), the device starts running + again, and per-minute billing resumes. On a device that is not parked this is a + no-op ready transition. + + 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._post( + path_template("/devices/{device_id}/resume", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def retrieve_capabilities( + 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, + ) -> DeviceRetrieveCapabilitiesResponse: + """Returns the set of capabilities supported by this device. + + For a legacy device + this reflects the live instance's actual tools rather than its static type; for + a core-managed device it is resolved from provider/pool configuration without + guaranteeing a live instance. Used to determine which tools and features are + available for the 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( + path_template("/devices/{device_id}/capabilities", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeviceRetrieveCapabilitiesResponse, + ) + def set_name( self, device_id: str, @@ -580,7 +719,7 @@ def set_name( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceSetNameResponse: """ Sets the display name for a device from the name in the request body and returns the updated device. @@ -602,7 +741,43 @@ def set_name( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceSetNameResponse, + ) + + def stop( + 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: + """ + Parks the device: its data, apps and identity are kept, but nothing runs and + nothing is billed until it is resumed. Only devices whose capabilities report + stop=true support this; others return 404. + + 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._post( + path_template("/devices/{device_id}/stop", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, ) def terminate( @@ -661,7 +836,7 @@ def wait_ready( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceWaitReadyResponse: """ Blocks until the device reaches the ready state, then returns the same payload as Get device info. The call returns early with an error if the wait is @@ -683,7 +858,7 @@ def wait_ready( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceWaitReadyResponse, ) @@ -740,6 +915,26 @@ def timezone(self) -> AsyncTimezoneResource: def language(self) -> AsyncLanguageResource: return AsyncLanguageResource(self._client) + @cached_property + def deep_link(self) -> AsyncDeepLinkResource: + return AsyncDeepLinkResource(self._client) + + @cached_property + def browser(self) -> AsyncBrowserResource: + return AsyncBrowserResource(self._client) + + @cached_property + def kiosk(self) -> AsyncKioskResource: + return AsyncKioskResource(self._client) + + @cached_property + def media_sessions(self) -> AsyncMediaSessionsResource: + return AsyncMediaSessionsResource(self._client) + + @cached_property + def recordings(self) -> AsyncRecordingsResource: + return AsyncRecordingsResource(self._client) + @cached_property def with_raw_response(self) -> AsyncDevicesResourceWithRawResponse: """ @@ -790,7 +985,7 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceCreateResponse: """ Requests a new device for the authenticated user from the device spec in the request body. Optional query parameters select the canonical device type, target @@ -856,7 +1051,7 @@ async def create( device_create_params.DeviceCreateParams, ), ), - cast_to=Device, + cast_to=DeviceCreateResponse, ) async def retrieve( @@ -869,7 +1064,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceRetrieveResponse: """ Returns the current state and metadata for a single device, including its lifecycle state, type, stream URL, billing strategy, and timestamps. A stream @@ -891,7 +1086,7 @@ async def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceRetrieveResponse, ) async def list( @@ -1121,6 +1316,81 @@ async def reset( cast_to=NoneType, ) + async def resume( + 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: + """ + Wakes a parked device: capacity is preflighted (the device's data may be + replicated to another node if its home is full), the device starts running + again, and per-minute billing resumes. On a device that is not parked this is a + no-op ready transition. + + 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._post( + path_template("/devices/{device_id}/resume", device_id=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 retrieve_capabilities( + 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, + ) -> DeviceRetrieveCapabilitiesResponse: + """Returns the set of capabilities supported by this device. + + For a legacy device + this reflects the live instance's actual tools rather than its static type; for + a core-managed device it is resolved from provider/pool configuration without + guaranteeing a live instance. Used to determine which tools and features are + available for the 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( + path_template("/devices/{device_id}/capabilities", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=DeviceRetrieveCapabilitiesResponse, + ) + async def set_name( self, device_id: str, @@ -1132,7 +1402,7 @@ async def set_name( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceSetNameResponse: """ Sets the display name for a device from the name in the request body and returns the updated device. @@ -1154,7 +1424,43 @@ async def set_name( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceSetNameResponse, + ) + + async def stop( + 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: + """ + Parks the device: its data, apps and identity are kept, but nothing runs and + nothing is billed until it is resumed. Only devices whose capabilities report + stop=true support this; others return 404. + + 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._post( + path_template("/devices/{device_id}/stop", device_id=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 terminate( @@ -1213,7 +1519,7 @@ async def wait_ready( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Device: + ) -> DeviceWaitReadyResponse: """ Blocks until the device reaches the ready state, then returns the same payload as Get device info. The call returns early with an error if the wait is @@ -1235,7 +1541,7 @@ async def wait_ready( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Device, + cast_to=DeviceWaitReadyResponse, ) @@ -1264,9 +1570,18 @@ def __init__(self, devices: DevicesResource) -> None: self.reset = to_raw_response_wrapper( devices.reset, ) + self.resume = to_raw_response_wrapper( + devices.resume, + ) + self.retrieve_capabilities = to_raw_response_wrapper( + devices.retrieve_capabilities, + ) self.set_name = to_raw_response_wrapper( devices.set_name, ) + self.stop = to_raw_response_wrapper( + devices.stop, + ) self.terminate = to_raw_response_wrapper( devices.terminate, ) @@ -1326,6 +1641,26 @@ def timezone(self) -> TimezoneResourceWithRawResponse: def language(self) -> LanguageResourceWithRawResponse: return LanguageResourceWithRawResponse(self._devices.language) + @cached_property + def deep_link(self) -> DeepLinkResourceWithRawResponse: + return DeepLinkResourceWithRawResponse(self._devices.deep_link) + + @cached_property + def browser(self) -> BrowserResourceWithRawResponse: + return BrowserResourceWithRawResponse(self._devices.browser) + + @cached_property + def kiosk(self) -> KioskResourceWithRawResponse: + return KioskResourceWithRawResponse(self._devices.kiosk) + + @cached_property + def media_sessions(self) -> MediaSessionsResourceWithRawResponse: + return MediaSessionsResourceWithRawResponse(self._devices.media_sessions) + + @cached_property + def recordings(self) -> RecordingsResourceWithRawResponse: + return RecordingsResourceWithRawResponse(self._devices.recordings) + class AsyncDevicesResourceWithRawResponse: def __init__(self, devices: AsyncDevicesResource) -> None: @@ -1352,9 +1687,18 @@ def __init__(self, devices: AsyncDevicesResource) -> None: self.reset = async_to_raw_response_wrapper( devices.reset, ) + self.resume = async_to_raw_response_wrapper( + devices.resume, + ) + self.retrieve_capabilities = async_to_raw_response_wrapper( + devices.retrieve_capabilities, + ) self.set_name = async_to_raw_response_wrapper( devices.set_name, ) + self.stop = async_to_raw_response_wrapper( + devices.stop, + ) self.terminate = async_to_raw_response_wrapper( devices.terminate, ) @@ -1414,6 +1758,26 @@ def timezone(self) -> AsyncTimezoneResourceWithRawResponse: def language(self) -> AsyncLanguageResourceWithRawResponse: return AsyncLanguageResourceWithRawResponse(self._devices.language) + @cached_property + def deep_link(self) -> AsyncDeepLinkResourceWithRawResponse: + return AsyncDeepLinkResourceWithRawResponse(self._devices.deep_link) + + @cached_property + def browser(self) -> AsyncBrowserResourceWithRawResponse: + return AsyncBrowserResourceWithRawResponse(self._devices.browser) + + @cached_property + def kiosk(self) -> AsyncKioskResourceWithRawResponse: + return AsyncKioskResourceWithRawResponse(self._devices.kiosk) + + @cached_property + def media_sessions(self) -> AsyncMediaSessionsResourceWithRawResponse: + return AsyncMediaSessionsResourceWithRawResponse(self._devices.media_sessions) + + @cached_property + def recordings(self) -> AsyncRecordingsResourceWithRawResponse: + return AsyncRecordingsResourceWithRawResponse(self._devices.recordings) + class DevicesResourceWithStreamingResponse: def __init__(self, devices: DevicesResource) -> None: @@ -1440,9 +1804,18 @@ def __init__(self, devices: DevicesResource) -> None: self.reset = to_streamed_response_wrapper( devices.reset, ) + self.resume = to_streamed_response_wrapper( + devices.resume, + ) + self.retrieve_capabilities = to_streamed_response_wrapper( + devices.retrieve_capabilities, + ) self.set_name = to_streamed_response_wrapper( devices.set_name, ) + self.stop = to_streamed_response_wrapper( + devices.stop, + ) self.terminate = to_streamed_response_wrapper( devices.terminate, ) @@ -1502,6 +1875,26 @@ def timezone(self) -> TimezoneResourceWithStreamingResponse: def language(self) -> LanguageResourceWithStreamingResponse: return LanguageResourceWithStreamingResponse(self._devices.language) + @cached_property + def deep_link(self) -> DeepLinkResourceWithStreamingResponse: + return DeepLinkResourceWithStreamingResponse(self._devices.deep_link) + + @cached_property + def browser(self) -> BrowserResourceWithStreamingResponse: + return BrowserResourceWithStreamingResponse(self._devices.browser) + + @cached_property + def kiosk(self) -> KioskResourceWithStreamingResponse: + return KioskResourceWithStreamingResponse(self._devices.kiosk) + + @cached_property + def media_sessions(self) -> MediaSessionsResourceWithStreamingResponse: + return MediaSessionsResourceWithStreamingResponse(self._devices.media_sessions) + + @cached_property + def recordings(self) -> RecordingsResourceWithStreamingResponse: + return RecordingsResourceWithStreamingResponse(self._devices.recordings) + class AsyncDevicesResourceWithStreamingResponse: def __init__(self, devices: AsyncDevicesResource) -> None: @@ -1528,9 +1921,18 @@ def __init__(self, devices: AsyncDevicesResource) -> None: self.reset = async_to_streamed_response_wrapper( devices.reset, ) + self.resume = async_to_streamed_response_wrapper( + devices.resume, + ) + self.retrieve_capabilities = async_to_streamed_response_wrapper( + devices.retrieve_capabilities, + ) self.set_name = async_to_streamed_response_wrapper( devices.set_name, ) + self.stop = async_to_streamed_response_wrapper( + devices.stop, + ) self.terminate = async_to_streamed_response_wrapper( devices.terminate, ) @@ -1589,3 +1991,23 @@ def timezone(self) -> AsyncTimezoneResourceWithStreamingResponse: @cached_property def language(self) -> AsyncLanguageResourceWithStreamingResponse: return AsyncLanguageResourceWithStreamingResponse(self._devices.language) + + @cached_property + def deep_link(self) -> AsyncDeepLinkResourceWithStreamingResponse: + return AsyncDeepLinkResourceWithStreamingResponse(self._devices.deep_link) + + @cached_property + def browser(self) -> AsyncBrowserResourceWithStreamingResponse: + return AsyncBrowserResourceWithStreamingResponse(self._devices.browser) + + @cached_property + def kiosk(self) -> AsyncKioskResourceWithStreamingResponse: + return AsyncKioskResourceWithStreamingResponse(self._devices.kiosk) + + @cached_property + def media_sessions(self) -> AsyncMediaSessionsResourceWithStreamingResponse: + return AsyncMediaSessionsResourceWithStreamingResponse(self._devices.media_sessions) + + @cached_property + def recordings(self) -> AsyncRecordingsResourceWithStreamingResponse: + return AsyncRecordingsResourceWithStreamingResponse(self._devices.recordings) diff --git a/src/mobilerun_sdk/resources/devices/esim/__init__.py b/src/mobilerun_sdk/resources/devices/esim/__init__.py new file mode 100644 index 00000000..12056c73 --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/esim/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .apn import ( + ApnResource, + AsyncApnResource, + ApnResourceWithRawResponse, + AsyncApnResourceWithRawResponse, + ApnResourceWithStreamingResponse, + AsyncApnResourceWithStreamingResponse, +) +from .esim import ( + EsimResource, + AsyncEsimResource, + EsimResourceWithRawResponse, + AsyncEsimResourceWithRawResponse, + EsimResourceWithStreamingResponse, + AsyncEsimResourceWithStreamingResponse, +) + +__all__ = [ + "ApnResource", + "AsyncApnResource", + "ApnResourceWithRawResponse", + "AsyncApnResourceWithRawResponse", + "ApnResourceWithStreamingResponse", + "AsyncApnResourceWithStreamingResponse", + "EsimResource", + "AsyncEsimResource", + "EsimResourceWithRawResponse", + "AsyncEsimResourceWithRawResponse", + "EsimResourceWithStreamingResponse", + "AsyncEsimResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/devices/esim/apn.py b/src/mobilerun_sdk/resources/devices/esim/apn.py new file mode 100644 index 00000000..38703c1f --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/esim/apn.py @@ -0,0 +1,437 @@ +# 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, path_template, 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.esim import apn_set_params, apn_select_params +from ....types.devices.esim.apn_list_response import ApnListResponse + +__all__ = ["ApnResource", "AsyncApnResource"] + + +class ApnResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ApnResourceWithRawResponse: + """ + 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 ApnResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ApnResourceWithStreamingResponse: + """ + 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 ApnResourceWithStreamingResponse(self) + + def list( + 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, + ) -> Optional[ApnListResponse]: + """ + Returns the access point names (APNs) configured for the device's active eSIM + subscriptions. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ApnListResponse, + ) + + def select( + self, + device_id: str, + *, + apn_id: int, + sub_id: 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: + """ + Marks an existing APN, identified by apnId, as the preferred APN for the given + eSIM subscription in the request body. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + body=maybe_transform( + { + "apn_id": apn_id, + "sub_id": sub_id, + }, + apn_select_params.ApnSelectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def set( + self, + device_id: str, + *, + apn: str, + mcc: str, + mnc: str, + name: str, + protocol: str, + roaming_protocol: str, + sub_id: int, + type: 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: + """ + Creates an access point name (APN) from the request body and applies it to the + given eSIM subscription. Type, protocol, and roaming protocol default to common + values when omitted. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + body=maybe_transform( + { + "apn": apn, + "mcc": mcc, + "mnc": mnc, + "name": name, + "protocol": protocol, + "roaming_protocol": roaming_protocol, + "sub_id": sub_id, + "type": type, + }, + apn_set_params.ApnSetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncApnResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncApnResourceWithRawResponse: + """ + 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 AsyncApnResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncApnResourceWithStreamingResponse: + """ + 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 AsyncApnResourceWithStreamingResponse(self) + + async def list( + 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, + ) -> Optional[ApnListResponse]: + """ + Returns the access point names (APNs) configured for the device's active eSIM + subscriptions. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ApnListResponse, + ) + + async def select( + self, + device_id: str, + *, + apn_id: int, + sub_id: 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: + """ + Marks an existing APN, identified by apnId, as the preferred APN for the given + eSIM subscription in the request body. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + body=await async_maybe_transform( + { + "apn_id": apn_id, + "sub_id": sub_id, + }, + apn_select_params.ApnSelectParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def set( + self, + device_id: str, + *, + apn: str, + mcc: str, + mnc: str, + name: str, + protocol: str, + roaming_protocol: str, + sub_id: int, + type: 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: + """ + Creates an access point name (APN) from the request body and applies it to the + given eSIM subscription. Type, protocol, and roaming protocol default to common + values when omitted. + + 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( + path_template("/devices/{device_id}/esim/apn", device_id=device_id), + body=await async_maybe_transform( + { + "apn": apn, + "mcc": mcc, + "mnc": mnc, + "name": name, + "protocol": protocol, + "roaming_protocol": roaming_protocol, + "sub_id": sub_id, + "type": type, + }, + apn_set_params.ApnSetParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ApnResourceWithRawResponse: + def __init__(self, apn: ApnResource) -> None: + self._apn = apn + + self.list = to_raw_response_wrapper( + apn.list, + ) + self.select = to_raw_response_wrapper( + apn.select, + ) + self.set = to_raw_response_wrapper( + apn.set, + ) + + +class AsyncApnResourceWithRawResponse: + def __init__(self, apn: AsyncApnResource) -> None: + self._apn = apn + + self.list = async_to_raw_response_wrapper( + apn.list, + ) + self.select = async_to_raw_response_wrapper( + apn.select, + ) + self.set = async_to_raw_response_wrapper( + apn.set, + ) + + +class ApnResourceWithStreamingResponse: + def __init__(self, apn: ApnResource) -> None: + self._apn = apn + + self.list = to_streamed_response_wrapper( + apn.list, + ) + self.select = to_streamed_response_wrapper( + apn.select, + ) + self.set = to_streamed_response_wrapper( + apn.set, + ) + + +class AsyncApnResourceWithStreamingResponse: + def __init__(self, apn: AsyncApnResource) -> None: + self._apn = apn + + self.list = async_to_streamed_response_wrapper( + apn.list, + ) + self.select = async_to_streamed_response_wrapper( + apn.select, + ) + self.set = async_to_streamed_response_wrapper( + apn.set, + ) diff --git a/src/mobilerun_sdk/resources/devices/esim.py b/src/mobilerun_sdk/resources/devices/esim/esim.py similarity index 67% rename from src/mobilerun_sdk/resources/devices/esim.py rename to src/mobilerun_sdk/resources/devices/esim/esim.py index 06abb252..924d895c 100644 --- a/src/mobilerun_sdk/resources/devices/esim.py +++ b/src/mobilerun_sdk/resources/devices/esim/esim.py @@ -6,25 +6,38 @@ import httpx -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import is_given, path_template, maybe_transform, strip_not_given, async_maybe_transform -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( +from .apn import ( + ApnResource, + AsyncApnResource, + ApnResourceWithRawResponse, + AsyncApnResourceWithRawResponse, + ApnResourceWithStreamingResponse, + AsyncApnResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import is_given, path_template, 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 esim_enable_params, esim_remove_params, esim_activate_params -from ...types.devices.esim_list_response import EsimListResponse -from ...types.devices.esim_activate_response import EsimActivateResponse +from ...._base_client import make_request_options +from ....types.devices import esim_enable_params, esim_remove_params, esim_activate_params, esim_set_roaming_params +from ....types.devices.esim_list_response import EsimListResponse +from ....types.devices.esim_status_response import EsimStatusResponse +from ....types.devices.esim_activate_response import EsimActivateResponse __all__ = ["EsimResource", "AsyncEsimResource"] class EsimResource(SyncAPIResource): + @cached_property + def apn(self) -> ApnResource: + return ApnResource(self._client) + @cached_property def with_raw_response(self) -> EsimResourceWithRawResponse: """ @@ -232,8 +245,96 @@ def remove( cast_to=NoneType, ) + def set_roaming( + self, + device_id: str, + *, + enabled: bool, + 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: + """ + Enables or disables data roaming for the device's eSIM based on the enabled flag + in the request body. + + 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( + path_template("/devices/{device_id}/esim/roaming", device_id=device_id), + body=maybe_transform({"enabled": enabled}, esim_set_roaming_params.EsimSetRoamingParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def status( + 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, + ) -> Optional[EsimStatusResponse]: + """ + Returns the connectivity status of the device's eSIM subscriptions. + + 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( + path_template("/devices/{device_id}/esim/status", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimStatusResponse, + ) + class AsyncEsimResource(AsyncAPIResource): + @cached_property + def apn(self) -> AsyncApnResource: + return AsyncApnResource(self._client) + @cached_property def with_raw_response(self) -> AsyncEsimResourceWithRawResponse: """ @@ -441,6 +542,90 @@ async def remove( cast_to=NoneType, ) + async def set_roaming( + self, + device_id: str, + *, + enabled: bool, + 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: + """ + Enables or disables data roaming for the device's eSIM based on the enabled flag + in the request body. + + 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( + path_template("/devices/{device_id}/esim/roaming", device_id=device_id), + body=await async_maybe_transform({"enabled": enabled}, esim_set_roaming_params.EsimSetRoamingParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def status( + 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, + ) -> Optional[EsimStatusResponse]: + """ + Returns the connectivity status of the device's eSIM subscriptions. + + 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( + path_template("/devices/{device_id}/esim/status", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimStatusResponse, + ) + class EsimResourceWithRawResponse: def __init__(self, esim: EsimResource) -> None: @@ -458,6 +643,16 @@ def __init__(self, esim: EsimResource) -> None: self.remove = to_raw_response_wrapper( esim.remove, ) + self.set_roaming = to_raw_response_wrapper( + esim.set_roaming, + ) + self.status = to_raw_response_wrapper( + esim.status, + ) + + @cached_property + def apn(self) -> ApnResourceWithRawResponse: + return ApnResourceWithRawResponse(self._esim.apn) class AsyncEsimResourceWithRawResponse: @@ -476,6 +671,16 @@ def __init__(self, esim: AsyncEsimResource) -> None: self.remove = async_to_raw_response_wrapper( esim.remove, ) + self.set_roaming = async_to_raw_response_wrapper( + esim.set_roaming, + ) + self.status = async_to_raw_response_wrapper( + esim.status, + ) + + @cached_property + def apn(self) -> AsyncApnResourceWithRawResponse: + return AsyncApnResourceWithRawResponse(self._esim.apn) class EsimResourceWithStreamingResponse: @@ -494,6 +699,16 @@ def __init__(self, esim: EsimResource) -> None: self.remove = to_streamed_response_wrapper( esim.remove, ) + self.set_roaming = to_streamed_response_wrapper( + esim.set_roaming, + ) + self.status = to_streamed_response_wrapper( + esim.status, + ) + + @cached_property + def apn(self) -> ApnResourceWithStreamingResponse: + return ApnResourceWithStreamingResponse(self._esim.apn) class AsyncEsimResourceWithStreamingResponse: @@ -512,3 +727,13 @@ def __init__(self, esim: AsyncEsimResource) -> None: self.remove = async_to_streamed_response_wrapper( esim.remove, ) + self.set_roaming = async_to_streamed_response_wrapper( + esim.set_roaming, + ) + self.status = async_to_streamed_response_wrapper( + esim.status, + ) + + @cached_property + def apn(self) -> AsyncApnResourceWithStreamingResponse: + return AsyncApnResourceWithStreamingResponse(self._esim.apn) diff --git a/src/mobilerun_sdk/resources/devices/kiosk.py b/src/mobilerun_sdk/resources/devices/kiosk.py new file mode 100644 index 00000000..8739ddca --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/kiosk.py @@ -0,0 +1,286 @@ +# 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, path_template, 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 kiosk_enable_params + +__all__ = ["KioskResource", "AsyncKioskResource"] + + +class KioskResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> KioskResourceWithRawResponse: + """ + 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 KioskResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> KioskResourceWithStreamingResponse: + """ + 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 KioskResourceWithStreamingResponse(self) + + def disable( + 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: + """ + Disables Android lock-task (kiosk) mode on the device, releasing it from the + locked 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._delete( + path_template("/devices/{device_id}/kiosk", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def enable( + 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: + """ + Locks the device to the package named in the request body using Android + lock-task (kiosk) mode, preventing the user from leaving the app. + + Args: + package_name: Package to lock the device to (Android lock-task mode). + + 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( + path_template("/devices/{device_id}/kiosk", device_id=device_id), + body=maybe_transform({"package_name": package_name}, kiosk_enable_params.KioskEnableParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncKioskResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncKioskResourceWithRawResponse: + """ + 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 AsyncKioskResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncKioskResourceWithStreamingResponse: + """ + 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 AsyncKioskResourceWithStreamingResponse(self) + + async def disable( + 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: + """ + Disables Android lock-task (kiosk) mode on the device, releasing it from the + locked 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._delete( + path_template("/devices/{device_id}/kiosk", device_id=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 enable( + 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: + """ + Locks the device to the package named in the request body using Android + lock-task (kiosk) mode, preventing the user from leaving the app. + + Args: + package_name: Package to lock the device to (Android lock-task mode). + + 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( + path_template("/devices/{device_id}/kiosk", device_id=device_id), + body=await async_maybe_transform({"package_name": package_name}, kiosk_enable_params.KioskEnableParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class KioskResourceWithRawResponse: + def __init__(self, kiosk: KioskResource) -> None: + self._kiosk = kiosk + + self.disable = to_raw_response_wrapper( + kiosk.disable, + ) + self.enable = to_raw_response_wrapper( + kiosk.enable, + ) + + +class AsyncKioskResourceWithRawResponse: + def __init__(self, kiosk: AsyncKioskResource) -> None: + self._kiosk = kiosk + + self.disable = async_to_raw_response_wrapper( + kiosk.disable, + ) + self.enable = async_to_raw_response_wrapper( + kiosk.enable, + ) + + +class KioskResourceWithStreamingResponse: + def __init__(self, kiosk: KioskResource) -> None: + self._kiosk = kiosk + + self.disable = to_streamed_response_wrapper( + kiosk.disable, + ) + self.enable = to_streamed_response_wrapper( + kiosk.enable, + ) + + +class AsyncKioskResourceWithStreamingResponse: + def __init__(self, kiosk: AsyncKioskResource) -> None: + self._kiosk = kiosk + + self.disable = async_to_streamed_response_wrapper( + kiosk.disable, + ) + self.enable = async_to_streamed_response_wrapper( + kiosk.enable, + ) diff --git a/src/mobilerun_sdk/resources/devices/location.py b/src/mobilerun_sdk/resources/devices/location.py index 1316b3fb..c63dd1d7 100644 --- a/src/mobilerun_sdk/resources/devices/location.py +++ b/src/mobilerun_sdk/resources/devices/location.py @@ -82,6 +82,48 @@ def get( cast_to=Location, ) + def reset( + 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: + """ + Clears any simulated GPS location and restores the device's default location + behavior. Devices without geo support return an unsupported-feature error. + + 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( + path_template("/devices/{device_id}/location", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + def set( self, device_id: str, @@ -195,6 +237,48 @@ async def get( cast_to=Location, ) + async def reset( + 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: + """ + Clears any simulated GPS location and restores the device's default location + behavior. Devices without geo support return an unsupported-feature error. + + 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( + path_template("/devices/{device_id}/location", device_id=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 set( self, device_id: str, @@ -254,6 +338,9 @@ def __init__(self, location: LocationResource) -> None: self.get = to_raw_response_wrapper( location.get, ) + self.reset = to_raw_response_wrapper( + location.reset, + ) self.set = to_raw_response_wrapper( location.set, ) @@ -266,6 +353,9 @@ def __init__(self, location: AsyncLocationResource) -> None: self.get = async_to_raw_response_wrapper( location.get, ) + self.reset = async_to_raw_response_wrapper( + location.reset, + ) self.set = async_to_raw_response_wrapper( location.set, ) @@ -278,6 +368,9 @@ def __init__(self, location: LocationResource) -> None: self.get = to_streamed_response_wrapper( location.get, ) + self.reset = to_streamed_response_wrapper( + location.reset, + ) self.set = to_streamed_response_wrapper( location.set, ) @@ -290,6 +383,9 @@ def __init__(self, location: AsyncLocationResource) -> None: self.get = async_to_streamed_response_wrapper( location.get, ) + self.reset = async_to_streamed_response_wrapper( + location.reset, + ) self.set = async_to_streamed_response_wrapper( location.set, ) diff --git a/src/mobilerun_sdk/resources/devices/media_sessions.py b/src/mobilerun_sdk/resources/devices/media_sessions.py new file mode 100644 index 00000000..ab9161e2 --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/media_sessions.py @@ -0,0 +1,469 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Query, Headers, NoneType, NotGiven, not_given +from ..._utils import path_template, 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 media_session_create_params +from ...types.devices.media_session_create_response import MediaSessionCreateResponse +from ...types.devices.media_session_activate_response import MediaSessionActivateResponse +from ...types.devices.media_session_retrieve_current_response import MediaSessionRetrieveCurrentResponse + +__all__ = ["MediaSessionsResource", "AsyncMediaSessionsResource"] + + +class MediaSessionsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MediaSessionsResourceWithRawResponse: + """ + 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 MediaSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MediaSessionsResourceWithStreamingResponse: + """ + 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 MediaSessionsResourceWithStreamingResponse(self) + + def create( + self, + device_id: str, + *, + camera: bool, + microphone: bool, + # 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, + ) -> MediaSessionCreateResponse: + """ + Allocates an exclusive relay path and returns one-time publish and control + credentials. The relay publisher must be established before activation. + + Args: + camera: Publish combined browser audio and H264 video into the device's virtual + microphone and camera. Requires microphone=true. + + microphone: Publish browser audio into the device's virtual microphone. + + 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._post( + path_template("/devices/{device_id}/media-sessions", device_id=device_id), + body=maybe_transform( + { + "camera": camera, + "microphone": microphone, + }, + media_session_create_params.MediaSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionCreateResponse, + ) + + def delete( + self, + session_id: str, + *, + device_id: str, + x_media_control_token: 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: + """ + Immediately revokes relay authorization, detaches virtual media inputs, and + kicks the relay publisher. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers.update({"X-Media-Control-Token": x_media_control_token}) + return self._delete( + path_template( + "/devices/{device_id}/media-sessions/{session_id}", device_id=device_id, session_id=session_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def activate( + self, + session_id: str, + *, + device_id: str, + x_media_control_token: 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, + ) -> MediaSessionActivateResponse: + """ + Validates relay codecs and attaches one private RTSP source to either the + virtual microphone or the combined microphone-and-camera pipeline. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"X-Media-Control-Token": x_media_control_token, **(extra_headers or {})} + return self._post( + path_template( + "/devices/{device_id}/media-sessions/{session_id}/activate", device_id=device_id, session_id=session_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionActivateResponse, + ) + + def retrieve_current( + 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, + ) -> MediaSessionRetrieveCurrentResponse: + """Returns status only. + + Publish URLs and credentials are never replayed after + creation. + + 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( + path_template("/devices/{device_id}/media-sessions/current", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionRetrieveCurrentResponse, + ) + + +class AsyncMediaSessionsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMediaSessionsResourceWithRawResponse: + """ + 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 AsyncMediaSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMediaSessionsResourceWithStreamingResponse: + """ + 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 AsyncMediaSessionsResourceWithStreamingResponse(self) + + async def create( + self, + device_id: str, + *, + camera: bool, + microphone: bool, + # 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, + ) -> MediaSessionCreateResponse: + """ + Allocates an exclusive relay path and returns one-time publish and control + credentials. The relay publisher must be established before activation. + + Args: + camera: Publish combined browser audio and H264 video into the device's virtual + microphone and camera. Requires microphone=true. + + microphone: Publish browser audio into the device's virtual microphone. + + 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._post( + path_template("/devices/{device_id}/media-sessions", device_id=device_id), + body=await async_maybe_transform( + { + "camera": camera, + "microphone": microphone, + }, + media_session_create_params.MediaSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionCreateResponse, + ) + + async def delete( + self, + session_id: str, + *, + device_id: str, + x_media_control_token: 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: + """ + Immediately revokes relay authorization, detaches virtual media inputs, and + kicks the relay publisher. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + extra_headers.update({"X-Media-Control-Token": x_media_control_token}) + return await self._delete( + path_template( + "/devices/{device_id}/media-sessions/{session_id}", device_id=device_id, session_id=session_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def activate( + self, + session_id: str, + *, + device_id: str, + x_media_control_token: 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, + ) -> MediaSessionActivateResponse: + """ + Validates relay codecs and attaches one private RTSP source to either the + virtual microphone or the combined microphone-and-camera pipeline. + + 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 session_id: + raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}") + extra_headers = {"X-Media-Control-Token": x_media_control_token, **(extra_headers or {})} + return await self._post( + path_template( + "/devices/{device_id}/media-sessions/{session_id}/activate", device_id=device_id, session_id=session_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionActivateResponse, + ) + + async def retrieve_current( + 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, + ) -> MediaSessionRetrieveCurrentResponse: + """Returns status only. + + Publish URLs and credentials are never replayed after + creation. + + 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( + path_template("/devices/{device_id}/media-sessions/current", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MediaSessionRetrieveCurrentResponse, + ) + + +class MediaSessionsResourceWithRawResponse: + def __init__(self, media_sessions: MediaSessionsResource) -> None: + self._media_sessions = media_sessions + + self.create = to_raw_response_wrapper( + media_sessions.create, + ) + self.delete = to_raw_response_wrapper( + media_sessions.delete, + ) + self.activate = to_raw_response_wrapper( + media_sessions.activate, + ) + self.retrieve_current = to_raw_response_wrapper( + media_sessions.retrieve_current, + ) + + +class AsyncMediaSessionsResourceWithRawResponse: + def __init__(self, media_sessions: AsyncMediaSessionsResource) -> None: + self._media_sessions = media_sessions + + self.create = async_to_raw_response_wrapper( + media_sessions.create, + ) + self.delete = async_to_raw_response_wrapper( + media_sessions.delete, + ) + self.activate = async_to_raw_response_wrapper( + media_sessions.activate, + ) + self.retrieve_current = async_to_raw_response_wrapper( + media_sessions.retrieve_current, + ) + + +class MediaSessionsResourceWithStreamingResponse: + def __init__(self, media_sessions: MediaSessionsResource) -> None: + self._media_sessions = media_sessions + + self.create = to_streamed_response_wrapper( + media_sessions.create, + ) + self.delete = to_streamed_response_wrapper( + media_sessions.delete, + ) + self.activate = to_streamed_response_wrapper( + media_sessions.activate, + ) + self.retrieve_current = to_streamed_response_wrapper( + media_sessions.retrieve_current, + ) + + +class AsyncMediaSessionsResourceWithStreamingResponse: + def __init__(self, media_sessions: AsyncMediaSessionsResource) -> None: + self._media_sessions = media_sessions + + self.create = async_to_streamed_response_wrapper( + media_sessions.create, + ) + self.delete = async_to_streamed_response_wrapper( + media_sessions.delete, + ) + self.activate = async_to_streamed_response_wrapper( + media_sessions.activate, + ) + self.retrieve_current = async_to_streamed_response_wrapper( + media_sessions.retrieve_current, + ) diff --git a/src/mobilerun_sdk/resources/devices/recordings.py b/src/mobilerun_sdk/resources/devices/recordings.py new file mode 100644 index 00000000..11ed0b6a --- /dev/null +++ b/src/mobilerun_sdk/resources/devices/recordings.py @@ -0,0 +1,744 @@ +# 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, SequenceNotStr, omit, not_given +from ..._utils import path_template, 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 recording_list_params, recording_start_params +from ...types.devices.recording_list_response import RecordingListResponse +from ...types.devices.recording_stop_response import RecordingStopResponse +from ...types.devices.recording_start_response import RecordingStartResponse +from ...types.devices.recording_status_response import RecordingStatusResponse + +__all__ = ["RecordingsResource", "AsyncRecordingsResource"] + + +class RecordingsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RecordingsResourceWithRawResponse: + """ + 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 RecordingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RecordingsResourceWithStreamingResponse: + """ + 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 RecordingsResourceWithStreamingResponse(self) + + def list( + self, + device_id: str, + *, + status: str | Omit = omit, + type: str | 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[RecordingListResponse]: + """ + List device recordings + + 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( + path_template("/devices/{device_id}/recordings", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "status": status, + "type": type, + }, + recording_list_params.RecordingListParams, + ), + ), + cast_to=RecordingListResponse, + ) + + def delete( + self, + recording_id: str, + *, + 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: + """ + Delete a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def start( + self, + device_id: str, + *, + name: str | Omit = omit, + retention_days: int | Omit = omit, + types: Optional[SequenceNotStr[str]] | 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, + ) -> RecordingStartResponse: + """ + Start a device recording + + 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._post( + path_template("/devices/{device_id}/recordings", device_id=device_id), + body=maybe_transform( + { + "name": name, + "retention_days": retention_days, + "types": types, + }, + recording_start_params.RecordingStartParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStartResponse, + ) + + def status( + self, + recording_id: str, + *, + 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, + ) -> RecordingStatusResponse: + """ + Get a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + return self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStatusResponse, + ) + + def stop( + self, + recording_id: str, + *, + 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, + ) -> RecordingStopResponse: + """ + Stop a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + return self._post( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStopResponse, + ) + + def trajectory( + self, + recording_id: str, + *, + 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: + """ + Get a device recording trajectory + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}/trajectory", + device_id=device_id, + recording_id=recording_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def video( + self, + recording_id: str, + *, + 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: + """ + Get a device recording video + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}/video", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncRecordingsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRecordingsResourceWithRawResponse: + """ + 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 AsyncRecordingsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRecordingsResourceWithStreamingResponse: + """ + 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 AsyncRecordingsResourceWithStreamingResponse(self) + + async def list( + self, + device_id: str, + *, + status: str | Omit = omit, + type: str | 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[RecordingListResponse]: + """ + List device recordings + + 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( + path_template("/devices/{device_id}/recordings", device_id=device_id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "status": status, + "type": type, + }, + recording_list_params.RecordingListParams, + ), + ), + cast_to=RecordingListResponse, + ) + + async def delete( + self, + recording_id: str, + *, + 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: + """ + Delete a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + 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, + device_id: str, + *, + name: str | Omit = omit, + retention_days: int | Omit = omit, + types: Optional[SequenceNotStr[str]] | 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, + ) -> RecordingStartResponse: + """ + Start a device recording + + 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._post( + path_template("/devices/{device_id}/recordings", device_id=device_id), + body=await async_maybe_transform( + { + "name": name, + "retention_days": retention_days, + "types": types, + }, + recording_start_params.RecordingStartParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStartResponse, + ) + + async def status( + self, + recording_id: str, + *, + 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, + ) -> RecordingStatusResponse: + """ + Get a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + return await self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStatusResponse, + ) + + async def stop( + self, + recording_id: str, + *, + 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, + ) -> RecordingStopResponse: + """ + Stop a device recording + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + return await self._post( + path_template( + "/devices/{device_id}/recordings/{recording_id}", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RecordingStopResponse, + ) + + async def trajectory( + self, + recording_id: str, + *, + 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: + """ + Get a device recording trajectory + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}/trajectory", + device_id=device_id, + recording_id=recording_id, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def video( + self, + recording_id: str, + *, + 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: + """ + Get a device recording video + + 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 recording_id: + raise ValueError(f"Expected a non-empty value for `recording_id` but received {recording_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._get( + path_template( + "/devices/{device_id}/recordings/{recording_id}/video", device_id=device_id, recording_id=recording_id + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class RecordingsResourceWithRawResponse: + def __init__(self, recordings: RecordingsResource) -> None: + self._recordings = recordings + + self.list = to_raw_response_wrapper( + recordings.list, + ) + self.delete = to_raw_response_wrapper( + recordings.delete, + ) + self.start = to_raw_response_wrapper( + recordings.start, + ) + self.status = to_raw_response_wrapper( + recordings.status, + ) + self.stop = to_raw_response_wrapper( + recordings.stop, + ) + self.trajectory = to_raw_response_wrapper( + recordings.trajectory, + ) + self.video = to_raw_response_wrapper( + recordings.video, + ) + + +class AsyncRecordingsResourceWithRawResponse: + def __init__(self, recordings: AsyncRecordingsResource) -> None: + self._recordings = recordings + + self.list = async_to_raw_response_wrapper( + recordings.list, + ) + self.delete = async_to_raw_response_wrapper( + recordings.delete, + ) + self.start = async_to_raw_response_wrapper( + recordings.start, + ) + self.status = async_to_raw_response_wrapper( + recordings.status, + ) + self.stop = async_to_raw_response_wrapper( + recordings.stop, + ) + self.trajectory = async_to_raw_response_wrapper( + recordings.trajectory, + ) + self.video = async_to_raw_response_wrapper( + recordings.video, + ) + + +class RecordingsResourceWithStreamingResponse: + def __init__(self, recordings: RecordingsResource) -> None: + self._recordings = recordings + + self.list = to_streamed_response_wrapper( + recordings.list, + ) + self.delete = to_streamed_response_wrapper( + recordings.delete, + ) + self.start = to_streamed_response_wrapper( + recordings.start, + ) + self.status = to_streamed_response_wrapper( + recordings.status, + ) + self.stop = to_streamed_response_wrapper( + recordings.stop, + ) + self.trajectory = to_streamed_response_wrapper( + recordings.trajectory, + ) + self.video = to_streamed_response_wrapper( + recordings.video, + ) + + +class AsyncRecordingsResourceWithStreamingResponse: + def __init__(self, recordings: AsyncRecordingsResource) -> None: + self._recordings = recordings + + self.list = async_to_streamed_response_wrapper( + recordings.list, + ) + self.delete = async_to_streamed_response_wrapper( + recordings.delete, + ) + self.start = async_to_streamed_response_wrapper( + recordings.start, + ) + self.status = async_to_streamed_response_wrapper( + recordings.status, + ) + self.stop = async_to_streamed_response_wrapper( + recordings.stop, + ) + self.trajectory = async_to_streamed_response_wrapper( + recordings.trajectory, + ) + self.video = async_to_streamed_response_wrapper( + recordings.video, + ) diff --git a/src/mobilerun_sdk/resources/esims/__init__.py b/src/mobilerun_sdk/resources/esims/__init__.py new file mode 100644 index 00000000..394c2d72 --- /dev/null +++ b/src/mobilerun_sdk/resources/esims/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .esims import ( + EsimsResource, + AsyncEsimsResource, + EsimsResourceWithRawResponse, + AsyncEsimsResourceWithRawResponse, + EsimsResourceWithStreamingResponse, + AsyncEsimsResourceWithStreamingResponse, +) +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) + +__all__ = [ + "MessagesResource", + "AsyncMessagesResource", + "MessagesResourceWithRawResponse", + "AsyncMessagesResourceWithRawResponse", + "MessagesResourceWithStreamingResponse", + "AsyncMessagesResourceWithStreamingResponse", + "EsimsResource", + "AsyncEsimsResource", + "EsimsResourceWithRawResponse", + "AsyncEsimsResourceWithRawResponse", + "EsimsResourceWithStreamingResponse", + "AsyncEsimsResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/esims/esims.py b/src/mobilerun_sdk/resources/esims/esims.py new file mode 100644 index 00000000..39132580 --- /dev/null +++ b/src/mobilerun_sdk/resources/esims/esims.py @@ -0,0 +1,1217 @@ +# 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 ...types import esim_list_params, esim_create_params, esim_import_params, esim_update_params, esim_install_params +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) +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.esim_list_response import EsimListResponse +from ...types.esim_create_response import EsimCreateResponse +from ...types.esim_import_response import EsimImportResponse +from ...types.esim_update_response import EsimUpdateResponse +from ...types.esim_install_response import EsimInstallResponse +from ...types.esim_capacity_response import EsimCapacityResponse +from ...types.esim_retrieve_response import EsimRetrieveResponse +from ...types.esim_selector_response import EsimSelectorResponse +from ...types.esim_install_status_response import EsimInstallStatusResponse +from ...types.esim_confirm_payment_response import EsimConfirmPaymentResponse + +__all__ = ["EsimsResource", "AsyncEsimsResource"] + + +class EsimsResource(SyncAPIResource): + @cached_property + def messages(self) -> MessagesResource: + return MessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> EsimsResourceWithRawResponse: + """ + 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 EsimsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> EsimsResourceWithStreamingResponse: + """ + 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 EsimsResourceWithStreamingResponse(self) + + def create( + self, + *, + idempotency_key: str | 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, + ) -> EsimCreateResponse: + """ + Purchases a physical eSIM from available inventory for the authenticated owner. + Returns 409 when no stock is available, or 402 with a billing checkout URL when + billing capacity is exhausted. + + Args: + idempotency_key: Client-supplied key; replaying the same key returns the original purchase + instead of buying again + + 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( + "/numbers/esims", + body=maybe_transform({"idempotency_key": idempotency_key}, esim_create_params.EsimCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimCreateResponse, + ) + + def retrieve( + self, + 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, + ) -> EsimRetrieveResponse: + """ + Retrieves a single physical eSIM. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/numbers/esims/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimRetrieveResponse, + ) + + def update( + self, + id: str, + *, + msisdn: Optional[str] | Omit = omit, + name: Optional[str] | 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, + ) -> EsimUpdateResponse: + """Updates the eSIM's self-reported msisdn and/or display name. + + Both fields are + optional, but the request body itself is required. Omitting a field leaves it + unchanged; setting it to null or an empty string clears it. `name` is capped at + 15 characters. Available regardless of the eSIM's current status. + + Args: + msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged; + null/empty clears it. An unverified label — never used for routing. + + name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit to leave unchanged; + null/empty/whitespace-only clears it. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._patch( + path_template("/numbers/esims/{id}", id=id), + body=maybe_transform( + { + "msisdn": msisdn, + "name": name, + }, + esim_update_params.EsimUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimUpdateResponse, + ) + + def list( + self, + *, + mine: Literal["true", "false"] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] + | 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, + ) -> EsimListResponse: + """ + Lists physical eSIMs owned by the authenticated owner. + + Args: + mine: Only include eSIMs created by the calling actor. + + 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( + "/numbers/esims", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "mine": mine, + "page": page, + "page_size": page_size, + "status": status, + }, + esim_list_params.EsimListParams, + ), + ), + cast_to=EsimListResponse, + ) + + def delete( + self, + 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: + """Removes a physical eSIM. + + Idempotent — returns 204 for a fresh removal or a + replay of an already-removed eSIM. An eSIM currently installed on a device is + uninstalled first, then removed. An eSIM in an intermediate install state + returns 409 `operator_resolution_required` and requires manual resolution. + Returns 404 if the eSIM doesn't exist or isn't owned by the caller. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/numbers/esims/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def capacity( + 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, + ) -> EsimCapacityResponse: + """ + Reports whether a free device is currently available, for pre-checking the + import flow before upload. This is a hint only, not a reservation — + `POST /esims/import` re-checks availability at submit time. + """ + return self._get( + "/numbers/esims/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimCapacityResponse, + ) + + def confirm_payment( + self, + 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, + ) -> EsimConfirmPaymentResponse: + """ + Checks for proof of payment for this eSIM's current rent and confirms it if + found. If no proof is available yet, returns 200 with the eSIM unchanged rather + than an error. Always returns the current eSIM 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/numbers/esims/{id}/confirm-payment", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimConfirmPaymentResponse, + ) + + def import_( + self, + *, + auto_install: bool | Omit = omit, + carrier_name: str | Omit = omit, + confirmation_code: str | Omit = omit, + country_code: str | Omit = omit, + device_id: str | Omit = omit, + idempotency_key: str | Omit = omit, + lpa_code: str | Omit = omit, + matching_id: str | Omit = omit, + msisdn: str | Omit = omit, + name: Optional[str] | Omit = omit, + notes: str | Omit = omit, + smdp_address: str | 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, + ) -> EsimImportResponse: + """ + Registers a bring-your-own (BYO) eSIM activation code as owned inventory. + Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or + `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets + a display label on the created eSIM (up to 15 characters). + + Subject to per-owner and daily import limits, and disabled entirely unless BYO + imports are enabled for this deployment (409 `byo_disabled`). Idempotent via + `idempotencyKey`: replaying the same key with an identical request returns the + original response; the same key with a different request returns 409 + `idempotency_conflict`. + + When rent-first billing is off (default), the import is free — 201 with the + eSIM. Setting `autoInstall: true` additionally dispatches an install immediately + after import (`deviceId` may only be set together with `autoInstall`): this + returns 202 with `{esim, operationId, statusUrl}` when the install claim + succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus + `installDispatch: {ok: false, reason}` when the install could not be dispatched + — the import itself still succeeds either way. + + When rent-first billing is on, import additionally requires available device + capacity (409 `device_pool_empty`) and is subject to a per-owner + awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is + created `awaiting_payment` and a checkout is started: 201 with + `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or + 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's + populated. Once payment is confirmed, install is triggered automatically. + + Args: + auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import. + No-op when ESIM_BYO_RENT_ENABLED=true. + + device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF. + Omit for a random pool device. + + idempotency_key: Client-supplied key; replaying the same key+request returns the original import + instead of importing again + + lpa_code: Full LPA activation code + + msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never + used for routing + + name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves + it unset. + + smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path. + + 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( + "/numbers/esims/import", + body=maybe_transform( + { + "auto_install": auto_install, + "carrier_name": carrier_name, + "confirmation_code": confirmation_code, + "country_code": country_code, + "device_id": device_id, + "idempotency_key": idempotency_key, + "lpa_code": lpa_code, + "matching_id": matching_id, + "msisdn": msisdn, + "name": name, + "notes": notes, + "smdp_address": smdp_address, + }, + esim_import_params.EsimImportParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimImportResponse, + ) + + def install( + self, + id: str, + *, + device_id: str | 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, + ) -> EsimInstallResponse: + """Installs the eSIM's activation code onto a device. + + `deviceId` is optional — omit + it to use an available device from the pool. This call is asynchronous: it + returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is + available by polling `GET /esims/{id}/install-status`. Retrying with the same + request is safe if a response is lost. + + Returns 409 when the eSIM is not in the `owned` state, or when no device is + currently available (see `reason`). When rent-first billing is enabled, a BYO + eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}` + instead. + + Args: + device_id: physedge device id to install the eSIM onto; omit for a random pool device + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/numbers/esims/{id}/install", id=id), + body=maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimInstallResponse, + ) + + def install_status( + self, + 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, + ) -> EsimInstallStatusResponse: + """ + Returns the eSIM's current install status, checking for a terminal outcome if an + install is still in progress. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/numbers/esims/{id}/install-status", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimInstallStatusResponse, + ) + + def selector( + 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, + ) -> EsimSelectorResponse: + """ + Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for + use in a message filter dropdown. Unlike `GET /esims`, this includes all + statuses, including retired eSIMs, and is not paginated. + """ + return self._get( + "/numbers/esims/selector", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimSelectorResponse, + ) + + +class AsyncEsimsResource(AsyncAPIResource): + @cached_property + def messages(self) -> AsyncMessagesResource: + return AsyncMessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncEsimsResourceWithRawResponse: + """ + 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 AsyncEsimsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncEsimsResourceWithStreamingResponse: + """ + 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 AsyncEsimsResourceWithStreamingResponse(self) + + async def create( + self, + *, + idempotency_key: str | 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, + ) -> EsimCreateResponse: + """ + Purchases a physical eSIM from available inventory for the authenticated owner. + Returns 409 when no stock is available, or 402 with a billing checkout URL when + billing capacity is exhausted. + + Args: + idempotency_key: Client-supplied key; replaying the same key returns the original purchase + instead of buying again + + 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( + "/numbers/esims", + body=await async_maybe_transform({"idempotency_key": idempotency_key}, esim_create_params.EsimCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimCreateResponse, + ) + + async def retrieve( + self, + 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, + ) -> EsimRetrieveResponse: + """ + Retrieves a single physical eSIM. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/numbers/esims/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimRetrieveResponse, + ) + + async def update( + self, + id: str, + *, + msisdn: Optional[str] | Omit = omit, + name: Optional[str] | 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, + ) -> EsimUpdateResponse: + """Updates the eSIM's self-reported msisdn and/or display name. + + Both fields are + optional, but the request body itself is required. Omitting a field leaves it + unchanged; setting it to null or an empty string clears it. `name` is capped at + 15 characters. Available regardless of the eSIM's current status. + + Args: + msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged; + null/empty clears it. An unverified label — never used for routing. + + name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit to leave unchanged; + null/empty/whitespace-only clears it. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._patch( + path_template("/numbers/esims/{id}", id=id), + body=await async_maybe_transform( + { + "msisdn": msisdn, + "name": name, + }, + esim_update_params.EsimUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimUpdateResponse, + ) + + async def list( + self, + *, + mine: Literal["true", "false"] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] + | 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, + ) -> EsimListResponse: + """ + Lists physical eSIMs owned by the authenticated owner. + + Args: + mine: Only include eSIMs created by the calling actor. + + 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( + "/numbers/esims", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "mine": mine, + "page": page, + "page_size": page_size, + "status": status, + }, + esim_list_params.EsimListParams, + ), + ), + cast_to=EsimListResponse, + ) + + async def delete( + self, + 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: + """Removes a physical eSIM. + + Idempotent — returns 204 for a fresh removal or a + replay of an already-removed eSIM. An eSIM currently installed on a device is + uninstalled first, then removed. An eSIM in an intermediate install state + returns 409 `operator_resolution_required` and requires manual resolution. + Returns 404 if the eSIM doesn't exist or isn't owned by the caller. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/numbers/esims/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def capacity( + 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, + ) -> EsimCapacityResponse: + """ + Reports whether a free device is currently available, for pre-checking the + import flow before upload. This is a hint only, not a reservation — + `POST /esims/import` re-checks availability at submit time. + """ + return await self._get( + "/numbers/esims/capacity", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimCapacityResponse, + ) + + async def confirm_payment( + self, + 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, + ) -> EsimConfirmPaymentResponse: + """ + Checks for proof of payment for this eSIM's current rent and confirms it if + found. If no proof is available yet, returns 200 with the eSIM unchanged rather + than an error. Always returns the current eSIM 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/numbers/esims/{id}/confirm-payment", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimConfirmPaymentResponse, + ) + + async def import_( + self, + *, + auto_install: bool | Omit = omit, + carrier_name: str | Omit = omit, + confirmation_code: str | Omit = omit, + country_code: str | Omit = omit, + device_id: str | Omit = omit, + idempotency_key: str | Omit = omit, + lpa_code: str | Omit = omit, + matching_id: str | Omit = omit, + msisdn: str | Omit = omit, + name: Optional[str] | Omit = omit, + notes: str | Omit = omit, + smdp_address: str | 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, + ) -> EsimImportResponse: + """ + Registers a bring-your-own (BYO) eSIM activation code as owned inventory. + Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or + `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets + a display label on the created eSIM (up to 15 characters). + + Subject to per-owner and daily import limits, and disabled entirely unless BYO + imports are enabled for this deployment (409 `byo_disabled`). Idempotent via + `idempotencyKey`: replaying the same key with an identical request returns the + original response; the same key with a different request returns 409 + `idempotency_conflict`. + + When rent-first billing is off (default), the import is free — 201 with the + eSIM. Setting `autoInstall: true` additionally dispatches an install immediately + after import (`deviceId` may only be set together with `autoInstall`): this + returns 202 with `{esim, operationId, statusUrl}` when the install claim + succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus + `installDispatch: {ok: false, reason}` when the install could not be dispatched + — the import itself still succeeds either way. + + When rent-first billing is on, import additionally requires available device + capacity (409 `device_pool_empty`) and is subject to a per-owner + awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is + created `awaiting_payment` and a checkout is started: 201 with + `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or + 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's + populated. Once payment is confirmed, install is triggered automatically. + + Args: + auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import. + No-op when ESIM_BYO_RENT_ENABLED=true. + + device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF. + Omit for a random pool device. + + idempotency_key: Client-supplied key; replaying the same key+request returns the original import + instead of importing again + + lpa_code: Full LPA activation code + + msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never + used for routing + + name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves + it unset. + + smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path. + + 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( + "/numbers/esims/import", + body=await async_maybe_transform( + { + "auto_install": auto_install, + "carrier_name": carrier_name, + "confirmation_code": confirmation_code, + "country_code": country_code, + "device_id": device_id, + "idempotency_key": idempotency_key, + "lpa_code": lpa_code, + "matching_id": matching_id, + "msisdn": msisdn, + "name": name, + "notes": notes, + "smdp_address": smdp_address, + }, + esim_import_params.EsimImportParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimImportResponse, + ) + + async def install( + self, + id: str, + *, + device_id: str | 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, + ) -> EsimInstallResponse: + """Installs the eSIM's activation code onto a device. + + `deviceId` is optional — omit + it to use an available device from the pool. This call is asynchronous: it + returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is + available by polling `GET /esims/{id}/install-status`. Retrying with the same + request is safe if a response is lost. + + Returns 409 when the eSIM is not in the `owned` state, or when no device is + currently available (see `reason`). When rent-first billing is enabled, a BYO + eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}` + instead. + + Args: + device_id: physedge device id to install the eSIM onto; omit for a random pool device + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/numbers/esims/{id}/install", id=id), + body=await async_maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimInstallResponse, + ) + + async def install_status( + self, + 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, + ) -> EsimInstallStatusResponse: + """ + Returns the eSIM's current install status, checking for a terminal outcome if an + install is still in progress. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/numbers/esims/{id}/install-status", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimInstallStatusResponse, + ) + + async def selector( + 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, + ) -> EsimSelectorResponse: + """ + Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for + use in a message filter dropdown. Unlike `GET /esims`, this includes all + statuses, including retired eSIMs, and is not paginated. + """ + return await self._get( + "/numbers/esims/selector", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=EsimSelectorResponse, + ) + + +class EsimsResourceWithRawResponse: + def __init__(self, esims: EsimsResource) -> None: + self._esims = esims + + self.create = to_raw_response_wrapper( + esims.create, + ) + self.retrieve = to_raw_response_wrapper( + esims.retrieve, + ) + self.update = to_raw_response_wrapper( + esims.update, + ) + self.list = to_raw_response_wrapper( + esims.list, + ) + self.delete = to_raw_response_wrapper( + esims.delete, + ) + self.capacity = to_raw_response_wrapper( + esims.capacity, + ) + self.confirm_payment = to_raw_response_wrapper( + esims.confirm_payment, + ) + self.import_ = to_raw_response_wrapper( + esims.import_, + ) + self.install = to_raw_response_wrapper( + esims.install, + ) + self.install_status = to_raw_response_wrapper( + esims.install_status, + ) + self.selector = to_raw_response_wrapper( + esims.selector, + ) + + @cached_property + def messages(self) -> MessagesResourceWithRawResponse: + return MessagesResourceWithRawResponse(self._esims.messages) + + +class AsyncEsimsResourceWithRawResponse: + def __init__(self, esims: AsyncEsimsResource) -> None: + self._esims = esims + + self.create = async_to_raw_response_wrapper( + esims.create, + ) + self.retrieve = async_to_raw_response_wrapper( + esims.retrieve, + ) + self.update = async_to_raw_response_wrapper( + esims.update, + ) + self.list = async_to_raw_response_wrapper( + esims.list, + ) + self.delete = async_to_raw_response_wrapper( + esims.delete, + ) + self.capacity = async_to_raw_response_wrapper( + esims.capacity, + ) + self.confirm_payment = async_to_raw_response_wrapper( + esims.confirm_payment, + ) + self.import_ = async_to_raw_response_wrapper( + esims.import_, + ) + self.install = async_to_raw_response_wrapper( + esims.install, + ) + self.install_status = async_to_raw_response_wrapper( + esims.install_status, + ) + self.selector = async_to_raw_response_wrapper( + esims.selector, + ) + + @cached_property + def messages(self) -> AsyncMessagesResourceWithRawResponse: + return AsyncMessagesResourceWithRawResponse(self._esims.messages) + + +class EsimsResourceWithStreamingResponse: + def __init__(self, esims: EsimsResource) -> None: + self._esims = esims + + self.create = to_streamed_response_wrapper( + esims.create, + ) + self.retrieve = to_streamed_response_wrapper( + esims.retrieve, + ) + self.update = to_streamed_response_wrapper( + esims.update, + ) + self.list = to_streamed_response_wrapper( + esims.list, + ) + self.delete = to_streamed_response_wrapper( + esims.delete, + ) + self.capacity = to_streamed_response_wrapper( + esims.capacity, + ) + self.confirm_payment = to_streamed_response_wrapper( + esims.confirm_payment, + ) + self.import_ = to_streamed_response_wrapper( + esims.import_, + ) + self.install = to_streamed_response_wrapper( + esims.install, + ) + self.install_status = to_streamed_response_wrapper( + esims.install_status, + ) + self.selector = to_streamed_response_wrapper( + esims.selector, + ) + + @cached_property + def messages(self) -> MessagesResourceWithStreamingResponse: + return MessagesResourceWithStreamingResponse(self._esims.messages) + + +class AsyncEsimsResourceWithStreamingResponse: + def __init__(self, esims: AsyncEsimsResource) -> None: + self._esims = esims + + self.create = async_to_streamed_response_wrapper( + esims.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + esims.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + esims.update, + ) + self.list = async_to_streamed_response_wrapper( + esims.list, + ) + self.delete = async_to_streamed_response_wrapper( + esims.delete, + ) + self.capacity = async_to_streamed_response_wrapper( + esims.capacity, + ) + self.confirm_payment = async_to_streamed_response_wrapper( + esims.confirm_payment, + ) + self.import_ = async_to_streamed_response_wrapper( + esims.import_, + ) + self.install = async_to_streamed_response_wrapper( + esims.install, + ) + self.install_status = async_to_streamed_response_wrapper( + esims.install_status, + ) + self.selector = async_to_streamed_response_wrapper( + esims.selector, + ) + + @cached_property + def messages(self) -> AsyncMessagesResourceWithStreamingResponse: + return AsyncMessagesResourceWithStreamingResponse(self._esims.messages) diff --git a/src/mobilerun_sdk/resources/esims/messages.py b/src/mobilerun_sdk/resources/esims/messages.py new file mode 100644 index 00000000..f6d7efad --- /dev/null +++ b/src/mobilerun_sdk/resources/esims/messages.py @@ -0,0 +1,352 @@ +# 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 path_template, 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 ...types.esims import message_list_params, message_send_params +from ..._base_client import make_request_options +from ...types.esims.message_list_response import MessageListResponse +from ...types.esims.message_send_response import MessageSendResponse + +__all__ = ["MessagesResource", "AsyncMessagesResource"] + + +class MessagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MessagesResourceWithRawResponse: + """ + 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 MessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: + """ + 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 MessagesResourceWithStreamingResponse(self) + + def list( + self, + id: str, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + number_id: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + peer_key: str | Omit = omit, + peer_number: str | Omit = omit, + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] + | 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, + ) -> MessageListResponse: + """ + List messages for one eSIM + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/numbers/esims/{id}/messages", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "direction": direction, + "number_id": number_id, + "page": page, + "page_size": page_size, + "peer_key": peer_key, + "peer_number": peer_number, + "status": status, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + def send( + self, + id: str, + *, + body: str, + to: str, + client_request_id: str | Omit = omit, + delivery_report: bool | 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, + ) -> MessageSendResponse: + """ + Send an SMS through one eSIM + + Args: + body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the + schema's own doc comment for why) + + to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); + rejected with 400 if it doesn't validate as E.164 afterward. + + client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the + same key + identical payload returns the original send; the same key with a + DIFFERENT payload is a 409 conflict. + + delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds + executor-side latency, never on this request — sends are always async/202). + Defaults to false for the public tier (opt-in, unlike the admin tier's + default-true). + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/numbers/esims/{id}/messages", id=id), + body=maybe_transform( + { + "body": body, + "to": to, + "client_request_id": client_request_id, + "delivery_report": delivery_report, + }, + message_send_params.MessageSendParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MessageSendResponse, + ) + + +class AsyncMessagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: + """ + 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 AsyncMessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: + """ + 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 AsyncMessagesResourceWithStreamingResponse(self) + + async def list( + self, + id: str, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + number_id: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + peer_key: str | Omit = omit, + peer_number: str | Omit = omit, + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] + | 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, + ) -> MessageListResponse: + """ + List messages for one eSIM + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/numbers/esims/{id}/messages", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "direction": direction, + "number_id": number_id, + "page": page, + "page_size": page_size, + "peer_key": peer_key, + "peer_number": peer_number, + "status": status, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + async def send( + self, + id: str, + *, + body: str, + to: str, + client_request_id: str | Omit = omit, + delivery_report: bool | 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, + ) -> MessageSendResponse: + """ + Send an SMS through one eSIM + + Args: + body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the + schema's own doc comment for why) + + to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); + rejected with 400 if it doesn't validate as E.164 afterward. + + client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the + same key + identical payload returns the original send; the same key with a + DIFFERENT payload is a 409 conflict. + + delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds + executor-side latency, never on this request — sends are always async/202). + Defaults to false for the public tier (opt-in, unlike the admin tier's + default-true). + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/numbers/esims/{id}/messages", id=id), + body=await async_maybe_transform( + { + "body": body, + "to": to, + "client_request_id": client_request_id, + "delivery_report": delivery_report, + }, + message_send_params.MessageSendParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MessageSendResponse, + ) + + +class MessagesResourceWithRawResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_raw_response_wrapper( + messages.list, + ) + self.send = to_raw_response_wrapper( + messages.send, + ) + + +class AsyncMessagesResourceWithRawResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_raw_response_wrapper( + messages.list, + ) + self.send = async_to_raw_response_wrapper( + messages.send, + ) + + +class MessagesResourceWithStreamingResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_streamed_response_wrapper( + messages.list, + ) + self.send = to_streamed_response_wrapper( + messages.send, + ) + + +class AsyncMessagesResourceWithStreamingResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_streamed_response_wrapper( + messages.list, + ) + self.send = async_to_streamed_response_wrapper( + messages.send, + ) diff --git a/src/mobilerun_sdk/resources/messages/__init__.py b/src/mobilerun_sdk/resources/messages/__init__.py new file mode 100644 index 00000000..35fae826 --- /dev/null +++ b/src/mobilerun_sdk/resources/messages/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) +from .conversations import ( + ConversationsResource, + AsyncConversationsResource, + ConversationsResourceWithRawResponse, + AsyncConversationsResourceWithRawResponse, + ConversationsResourceWithStreamingResponse, + AsyncConversationsResourceWithStreamingResponse, +) + +__all__ = [ + "ConversationsResource", + "AsyncConversationsResource", + "ConversationsResourceWithRawResponse", + "AsyncConversationsResourceWithRawResponse", + "ConversationsResourceWithStreamingResponse", + "AsyncConversationsResourceWithStreamingResponse", + "MessagesResource", + "AsyncMessagesResource", + "MessagesResourceWithRawResponse", + "AsyncMessagesResourceWithRawResponse", + "MessagesResourceWithStreamingResponse", + "AsyncMessagesResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/messages/conversations.py b/src/mobilerun_sdk/resources/messages/conversations.py new file mode 100644 index 00000000..9ef14bfa --- /dev/null +++ b/src/mobilerun_sdk/resources/messages/conversations.py @@ -0,0 +1,331 @@ +# 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 + +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.messages import conversation_list_params, conversation_mark_read_params +from ...types.messages.conversation_list_response import ConversationListResponse +from ...types.messages.conversation_mark_read_response import ConversationMarkReadResponse + +__all__ = ["ConversationsResource", "AsyncConversationsResource"] + + +class ConversationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ConversationsResourceWithRawResponse: + """ + 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 ConversationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ConversationsResourceWithStreamingResponse: + """ + 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 ConversationsResourceWithStreamingResponse(self) + + def list( + self, + *, + cursor_last_message_id: str | Omit = omit, + cursor_last_occurred_at: Union[str, datetime] | Omit = omit, + esim_id: str | Omit = omit, + limit: int | Omit = omit, + number_id: str | 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, + ) -> ConversationListResponse: + """Lists the caller's own SMS conversations, one row per thread. + + Each row includes + the most recent message in the thread, its unread inbound count, and the eSIMs + it was seen through. Optional `esimId` or `numberId` narrows to threads on one + eSIM or number. + + Cursor-paginated via `limit` (default 20, max 100) and + `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from + a previous page's `nextCursor`). Pagination follows each thread's most recent + activity rather than a fixed snapshot, so a thread with new activity can move + ahead of an in-progress page fetch. Clients that need a stable ordering should + snapshot their own view. + + 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( + "/numbers/messages/conversations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "cursor_last_message_id": cursor_last_message_id, + "cursor_last_occurred_at": cursor_last_occurred_at, + "esim_id": esim_id, + "limit": limit, + "number_id": number_id, + }, + conversation_list_params.ConversationListParams, + ), + ), + cast_to=ConversationListResponse, + ) + + def mark_read( + self, + *, + peer_key: str, + up_to_message_id: str, + up_to_occurred_at: Union[str, datetime], + # 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, + ) -> ConversationMarkReadResponse: + """ + Marks the caller's own inbound messages in a conversation thread as read, up to + and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a + conversation row's `lastMessage`. Idempotent: repeating the call with the same + cursor updates 0 rows. Returns the number of rows updated. + + Args: + peer_key: The thread's canonical peer key (see GET .../conversations) + + up_to_occurred_at: Mark inbound messages read up to (and including) this occurredAt/upToMessageId + cursor + + 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( + "/numbers/messages/conversations/read", + body=maybe_transform( + { + "peer_key": peer_key, + "up_to_message_id": up_to_message_id, + "up_to_occurred_at": up_to_occurred_at, + }, + conversation_mark_read_params.ConversationMarkReadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConversationMarkReadResponse, + ) + + +class AsyncConversationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncConversationsResourceWithRawResponse: + """ + 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 AsyncConversationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncConversationsResourceWithStreamingResponse: + """ + 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 AsyncConversationsResourceWithStreamingResponse(self) + + async def list( + self, + *, + cursor_last_message_id: str | Omit = omit, + cursor_last_occurred_at: Union[str, datetime] | Omit = omit, + esim_id: str | Omit = omit, + limit: int | Omit = omit, + number_id: str | 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, + ) -> ConversationListResponse: + """Lists the caller's own SMS conversations, one row per thread. + + Each row includes + the most recent message in the thread, its unread inbound count, and the eSIMs + it was seen through. Optional `esimId` or `numberId` narrows to threads on one + eSIM or number. + + Cursor-paginated via `limit` (default 20, max 100) and + `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from + a previous page's `nextCursor`). Pagination follows each thread's most recent + activity rather than a fixed snapshot, so a thread with new activity can move + ahead of an in-progress page fetch. Clients that need a stable ordering should + snapshot their own view. + + 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( + "/numbers/messages/conversations", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "cursor_last_message_id": cursor_last_message_id, + "cursor_last_occurred_at": cursor_last_occurred_at, + "esim_id": esim_id, + "limit": limit, + "number_id": number_id, + }, + conversation_list_params.ConversationListParams, + ), + ), + cast_to=ConversationListResponse, + ) + + async def mark_read( + self, + *, + peer_key: str, + up_to_message_id: str, + up_to_occurred_at: Union[str, datetime], + # 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, + ) -> ConversationMarkReadResponse: + """ + Marks the caller's own inbound messages in a conversation thread as read, up to + and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a + conversation row's `lastMessage`. Idempotent: repeating the call with the same + cursor updates 0 rows. Returns the number of rows updated. + + Args: + peer_key: The thread's canonical peer key (see GET .../conversations) + + up_to_occurred_at: Mark inbound messages read up to (and including) this occurredAt/upToMessageId + cursor + + 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( + "/numbers/messages/conversations/read", + body=await async_maybe_transform( + { + "peer_key": peer_key, + "up_to_message_id": up_to_message_id, + "up_to_occurred_at": up_to_occurred_at, + }, + conversation_mark_read_params.ConversationMarkReadParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ConversationMarkReadResponse, + ) + + +class ConversationsResourceWithRawResponse: + def __init__(self, conversations: ConversationsResource) -> None: + self._conversations = conversations + + self.list = to_raw_response_wrapper( + conversations.list, + ) + self.mark_read = to_raw_response_wrapper( + conversations.mark_read, + ) + + +class AsyncConversationsResourceWithRawResponse: + def __init__(self, conversations: AsyncConversationsResource) -> None: + self._conversations = conversations + + self.list = async_to_raw_response_wrapper( + conversations.list, + ) + self.mark_read = async_to_raw_response_wrapper( + conversations.mark_read, + ) + + +class ConversationsResourceWithStreamingResponse: + def __init__(self, conversations: ConversationsResource) -> None: + self._conversations = conversations + + self.list = to_streamed_response_wrapper( + conversations.list, + ) + self.mark_read = to_streamed_response_wrapper( + conversations.mark_read, + ) + + +class AsyncConversationsResourceWithStreamingResponse: + def __init__(self, conversations: AsyncConversationsResource) -> None: + self._conversations = conversations + + self.list = async_to_streamed_response_wrapper( + conversations.list, + ) + self.mark_read = async_to_streamed_response_wrapper( + conversations.mark_read, + ) diff --git a/src/mobilerun_sdk/resources/messages/messages.py b/src/mobilerun_sdk/resources/messages/messages.py new file mode 100644 index 00000000..2e5f30b6 --- /dev/null +++ b/src/mobilerun_sdk/resources/messages/messages.py @@ -0,0 +1,255 @@ +# 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 message_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 ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .conversations import ( + ConversationsResource, + AsyncConversationsResource, + ConversationsResourceWithRawResponse, + AsyncConversationsResourceWithRawResponse, + ConversationsResourceWithStreamingResponse, + AsyncConversationsResourceWithStreamingResponse, +) +from ..._base_client import make_request_options +from ...types.message_list_response import MessageListResponse + +__all__ = ["MessagesResource", "AsyncMessagesResource"] + + +class MessagesResource(SyncAPIResource): + @cached_property + def conversations(self) -> ConversationsResource: + return ConversationsResource(self._client) + + @cached_property + def with_raw_response(self) -> MessagesResourceWithRawResponse: + """ + 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 MessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: + """ + 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 MessagesResourceWithStreamingResponse(self) + + def list( + self, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + esim_id: str | Omit = omit, + number_id: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + peer_key: str | Omit = omit, + peer_number: str | Omit = omit, + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] + | 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, + ) -> MessageListResponse: + """Lists the caller's own SMS messages, newest first. + + Supports filtering by + direction, esimId, numberId, status, peerNumber (substring search, min 3 + characters), and peerKey (exact thread match). Each row includes its canonical + thread key (`peerKey`). + + 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( + "/numbers/messages", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "direction": direction, + "esim_id": esim_id, + "number_id": number_id, + "page": page, + "page_size": page_size, + "peer_key": peer_key, + "peer_number": peer_number, + "status": status, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + +class AsyncMessagesResource(AsyncAPIResource): + @cached_property + def conversations(self) -> AsyncConversationsResource: + return AsyncConversationsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: + """ + 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 AsyncMessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: + """ + 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 AsyncMessagesResourceWithStreamingResponse(self) + + async def list( + self, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + esim_id: str | Omit = omit, + number_id: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + peer_key: str | Omit = omit, + peer_number: str | Omit = omit, + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] + | 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, + ) -> MessageListResponse: + """Lists the caller's own SMS messages, newest first. + + Supports filtering by + direction, esimId, numberId, status, peerNumber (substring search, min 3 + characters), and peerKey (exact thread match). Each row includes its canonical + thread key (`peerKey`). + + 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( + "/numbers/messages", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "direction": direction, + "esim_id": esim_id, + "number_id": number_id, + "page": page, + "page_size": page_size, + "peer_key": peer_key, + "peer_number": peer_number, + "status": status, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + +class MessagesResourceWithRawResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_raw_response_wrapper( + messages.list, + ) + + @cached_property + def conversations(self) -> ConversationsResourceWithRawResponse: + return ConversationsResourceWithRawResponse(self._messages.conversations) + + +class AsyncMessagesResourceWithRawResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_raw_response_wrapper( + messages.list, + ) + + @cached_property + def conversations(self) -> AsyncConversationsResourceWithRawResponse: + return AsyncConversationsResourceWithRawResponse(self._messages.conversations) + + +class MessagesResourceWithStreamingResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_streamed_response_wrapper( + messages.list, + ) + + @cached_property + def conversations(self) -> ConversationsResourceWithStreamingResponse: + return ConversationsResourceWithStreamingResponse(self._messages.conversations) + + +class AsyncMessagesResourceWithStreamingResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_streamed_response_wrapper( + messages.list, + ) + + @cached_property + def conversations(self) -> AsyncConversationsResourceWithStreamingResponse: + return AsyncConversationsResourceWithStreamingResponse(self._messages.conversations) diff --git a/src/mobilerun_sdk/resources/notifications.py b/src/mobilerun_sdk/resources/notifications.py new file mode 100644 index 00000000..80c615c8 --- /dev/null +++ b/src/mobilerun_sdk/resources/notifications.py @@ -0,0 +1,293 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import notification_update_preferences_params +from .._types import Body, Query, Headers, NotGiven, SequenceNotStr, 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.notification_catalog_response import NotificationCatalogResponse +from ..types.notification_get_preferences_response import NotificationGetPreferencesResponse +from ..types.notification_update_preferences_response import NotificationUpdatePreferencesResponse + +__all__ = ["NotificationsResource", "AsyncNotificationsResource"] + + +class NotificationsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> NotificationsResourceWithRawResponse: + """ + 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 NotificationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NotificationsResourceWithStreamingResponse: + """ + 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 NotificationsResourceWithStreamingResponse(self) + + def catalog( + 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, + ) -> NotificationCatalogResponse: + """Returns the catalog of notifiable event types grouped by source category. + + Each + event lists its type identifier, label, and description, which can be referenced + when muting event types in notification preferences. + """ + return self._get( + "/notifications/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationCatalogResponse, + ) + + def get_preferences( + 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, + ) -> NotificationGetPreferencesResponse: + """ + Returns your current notification preferences, expressed as the list of event + types you have muted. An empty list means notifications are enabled for all + notifiable event types. + """ + return self._get( + "/notifications/preferences", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationGetPreferencesResponse, + ) + + def update_preferences( + self, + *, + muted_types: SequenceNotStr[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, + ) -> NotificationUpdatePreferencesResponse: + """Replaces your set of muted event types with the supplied list. + + Any unknown or + non-notifiable types are dropped, and the response returns the muted types that + were actually stored. + + 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._patch( + "/notifications/preferences", + body=maybe_transform( + {"muted_types": muted_types}, notification_update_preferences_params.NotificationUpdatePreferencesParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationUpdatePreferencesResponse, + ) + + +class AsyncNotificationsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncNotificationsResourceWithRawResponse: + """ + 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 AsyncNotificationsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNotificationsResourceWithStreamingResponse: + """ + 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 AsyncNotificationsResourceWithStreamingResponse(self) + + async def catalog( + 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, + ) -> NotificationCatalogResponse: + """Returns the catalog of notifiable event types grouped by source category. + + Each + event lists its type identifier, label, and description, which can be referenced + when muting event types in notification preferences. + """ + return await self._get( + "/notifications/catalog", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationCatalogResponse, + ) + + async def get_preferences( + 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, + ) -> NotificationGetPreferencesResponse: + """ + Returns your current notification preferences, expressed as the list of event + types you have muted. An empty list means notifications are enabled for all + notifiable event types. + """ + return await self._get( + "/notifications/preferences", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationGetPreferencesResponse, + ) + + async def update_preferences( + self, + *, + muted_types: SequenceNotStr[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, + ) -> NotificationUpdatePreferencesResponse: + """Replaces your set of muted event types with the supplied list. + + Any unknown or + non-notifiable types are dropped, and the response returns the muted types that + were actually stored. + + 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._patch( + "/notifications/preferences", + body=await async_maybe_transform( + {"muted_types": muted_types}, notification_update_preferences_params.NotificationUpdatePreferencesParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NotificationUpdatePreferencesResponse, + ) + + +class NotificationsResourceWithRawResponse: + def __init__(self, notifications: NotificationsResource) -> None: + self._notifications = notifications + + self.catalog = to_raw_response_wrapper( + notifications.catalog, + ) + self.get_preferences = to_raw_response_wrapper( + notifications.get_preferences, + ) + self.update_preferences = to_raw_response_wrapper( + notifications.update_preferences, + ) + + +class AsyncNotificationsResourceWithRawResponse: + def __init__(self, notifications: AsyncNotificationsResource) -> None: + self._notifications = notifications + + self.catalog = async_to_raw_response_wrapper( + notifications.catalog, + ) + self.get_preferences = async_to_raw_response_wrapper( + notifications.get_preferences, + ) + self.update_preferences = async_to_raw_response_wrapper( + notifications.update_preferences, + ) + + +class NotificationsResourceWithStreamingResponse: + def __init__(self, notifications: NotificationsResource) -> None: + self._notifications = notifications + + self.catalog = to_streamed_response_wrapper( + notifications.catalog, + ) + self.get_preferences = to_streamed_response_wrapper( + notifications.get_preferences, + ) + self.update_preferences = to_streamed_response_wrapper( + notifications.update_preferences, + ) + + +class AsyncNotificationsResourceWithStreamingResponse: + def __init__(self, notifications: AsyncNotificationsResource) -> None: + self._notifications = notifications + + self.catalog = async_to_streamed_response_wrapper( + notifications.catalog, + ) + self.get_preferences = async_to_streamed_response_wrapper( + notifications.get_preferences, + ) + self.update_preferences = async_to_streamed_response_wrapper( + notifications.update_preferences, + ) diff --git a/src/mobilerun_sdk/resources/numbers/__init__.py b/src/mobilerun_sdk/resources/numbers/__init__.py new file mode 100644 index 00000000..64e53a01 --- /dev/null +++ b/src/mobilerun_sdk/resources/numbers/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .numbers import ( + NumbersResource, + AsyncNumbersResource, + NumbersResourceWithRawResponse, + AsyncNumbersResourceWithRawResponse, + NumbersResourceWithStreamingResponse, + AsyncNumbersResourceWithStreamingResponse, +) +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) + +__all__ = [ + "MessagesResource", + "AsyncMessagesResource", + "MessagesResourceWithRawResponse", + "AsyncMessagesResourceWithRawResponse", + "MessagesResourceWithStreamingResponse", + "AsyncMessagesResourceWithStreamingResponse", + "NumbersResource", + "AsyncNumbersResource", + "NumbersResourceWithRawResponse", + "AsyncNumbersResourceWithRawResponse", + "NumbersResourceWithStreamingResponse", + "AsyncNumbersResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/numbers/messages.py b/src/mobilerun_sdk/resources/numbers/messages.py new file mode 100644 index 00000000..123fdd0a --- /dev/null +++ b/src/mobilerun_sdk/resources/numbers/messages.py @@ -0,0 +1,205 @@ +# 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 Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, 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.numbers import message_list_params +from ...types.numbers.message_list_response import MessageListResponse + +__all__ = ["MessagesResource", "AsyncMessagesResource"] + + +class MessagesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> MessagesResourceWithRawResponse: + """ + 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 MessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: + """ + 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 MessagesResourceWithStreamingResponse(self) + + def list( + self, + id: str, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + since: 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MessageListResponse: + """ + Returns SMS messages on the number, inbound and outbound, scoped to the + authenticated user. Newest first. Messages stay with the number across device + switches. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/numbers/phones/{id}/messages", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "direction": direction, + "page": page, + "page_size": page_size, + "since": since, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + +class AsyncMessagesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: + """ + 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 AsyncMessagesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: + """ + 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 AsyncMessagesResourceWithStreamingResponse(self) + + async def list( + self, + id: str, + *, + direction: Literal["all", "inbound", "outbound"] | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + since: 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MessageListResponse: + """ + Returns SMS messages on the number, inbound and outbound, scoped to the + authenticated user. Newest first. Messages stay with the number across device + switches. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/numbers/phones/{id}/messages", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "direction": direction, + "page": page, + "page_size": page_size, + "since": since, + }, + message_list_params.MessageListParams, + ), + ), + cast_to=MessageListResponse, + ) + + +class MessagesResourceWithRawResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_raw_response_wrapper( + messages.list, + ) + + +class AsyncMessagesResourceWithRawResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_raw_response_wrapper( + messages.list, + ) + + +class MessagesResourceWithStreamingResponse: + def __init__(self, messages: MessagesResource) -> None: + self._messages = messages + + self.list = to_streamed_response_wrapper( + messages.list, + ) + + +class AsyncMessagesResourceWithStreamingResponse: + def __init__(self, messages: AsyncMessagesResource) -> None: + self._messages = messages + + self.list = async_to_streamed_response_wrapper( + messages.list, + ) diff --git a/src/mobilerun_sdk/resources/numbers/numbers.py b/src/mobilerun_sdk/resources/numbers/numbers.py new file mode 100644 index 00000000..2ec46354 --- /dev/null +++ b/src/mobilerun_sdk/resources/numbers/numbers.py @@ -0,0 +1,644 @@ +# 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 number_list_params, number_create_params +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform +from .messages import ( + MessagesResource, + AsyncMessagesResource, + MessagesResourceWithRawResponse, + AsyncMessagesResourceWithRawResponse, + MessagesResourceWithStreamingResponse, + AsyncMessagesResourceWithStreamingResponse, +) +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.number_list_response import NumberListResponse +from ...types.number_create_response import NumberCreateResponse +from ...types.number_delete_response import NumberDeleteResponse +from ...types.number_purposes_response import NumberPurposesResponse +from ...types.number_retrieve_response import NumberRetrieveResponse +from ...types.number_countries_response import NumberCountriesResponse + +__all__ = ["NumbersResource", "AsyncNumbersResource"] + + +class NumbersResource(SyncAPIResource): + @cached_property + def messages(self) -> MessagesResource: + return MessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> NumbersResourceWithRawResponse: + """ + 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 NumbersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> NumbersResourceWithStreamingResponse: + """ + 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 NumbersResourceWithStreamingResponse(self) + + def create( + self, + *, + billing_preference: Literal["included", "rent"] | Omit = omit, + country: str | Omit = omit, + purpose: str | Omit = omit, + idempotency_key: str | 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, + ) -> NumberCreateResponse: + """Starts a Mobilerun Phone purchase for the authenticated owner. + + Accepted requests + always return the same asynchronous envelope; poll GET /numbers/phones/{id} for + its business state. `purpose` and `country` are mutually exclusive. + + Args: + billing_preference: Prefer a free package seat ('included', default) or force the paid checkout + ('rent') + + country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be + combined with `purpose`. + + purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes. + + idempotency_key: Optional request idempotency key. + + 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 + """ + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} + return self._post( + "/numbers/phones", + body=maybe_transform( + { + "billing_preference": billing_preference, + "country": country, + "purpose": purpose, + }, + number_create_params.NumberCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberCreateResponse, + ) + + def retrieve( + self, + 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, + ) -> NumberRetrieveResponse: + """ + Retrieves a single phone number. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/numbers/phones/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberRetrieveResponse, + ) + + 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NumberListResponse: + """ + Lists phone numbers owned by the authenticated user — both BYO (`user`) and + provisioned (`mobilerun`) numbers. + + 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( + "/numbers/phones", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "page": page, + "page_size": page_size, + }, + number_list_params.NumberListParams, + ), + ), + cast_to=NumberListResponse, + ) + + def delete( + self, + 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, + ) -> NumberDeleteResponse: + """Cancels a Mobilerun Phone. + + The outcome depends on the number's current state: + + - If the number is still awaiting payment and no payment for it is currently + being processed, the checkout is closed immediately and the number is retired. + - If the number is on the standard paid plan and already paid and in service, + cancellation is scheduled for the end of the current billing period rather + than taking effect immediately. The number stays usable through the period + already paid for, with no partial refund. Calling this again while a + cancellation is already scheduled is a no-op that returns the same result. The + response's `state` reflects this as `cancel_scheduled` with + `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing + confirms the cancellation. + + Any other state (already refunding, a permanent billing failure, a payment + currently being processed, an included-plan number, or a non-hosted/BYO number) + returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't + owned by the caller. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._delete( + path_template("/numbers/phones/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberDeleteResponse, + ) + + def countries( + 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, + ) -> NumberCountriesResponse: + """ + Lists the countries currently offered for a dedicated Mobilerun Phone, with live + stock status. Pass `country` as the `country` field on POST /numbers/phones. + """ + return self._get( + "/numbers/phones/countries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberCountriesResponse, + ) + + def purposes( + 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, + ) -> NumberPurposesResponse: + """Lists the optional purposes currently available for a Mobilerun Phone.""" + return self._get( + "/numbers/phones/purposes", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberPurposesResponse, + ) + + +class AsyncNumbersResource(AsyncAPIResource): + @cached_property + def messages(self) -> AsyncMessagesResource: + return AsyncMessagesResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncNumbersResourceWithRawResponse: + """ + 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 AsyncNumbersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncNumbersResourceWithStreamingResponse: + """ + 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 AsyncNumbersResourceWithStreamingResponse(self) + + async def create( + self, + *, + billing_preference: Literal["included", "rent"] | Omit = omit, + country: str | Omit = omit, + purpose: str | Omit = omit, + idempotency_key: str | 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, + ) -> NumberCreateResponse: + """Starts a Mobilerun Phone purchase for the authenticated owner. + + Accepted requests + always return the same asynchronous envelope; poll GET /numbers/phones/{id} for + its business state. `purpose` and `country` are mutually exclusive. + + Args: + billing_preference: Prefer a free package seat ('included', default) or force the paid checkout + ('rent') + + country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be + combined with `purpose`. + + purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes. + + idempotency_key: Optional request idempotency key. + + 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 + """ + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} + return await self._post( + "/numbers/phones", + body=await async_maybe_transform( + { + "billing_preference": billing_preference, + "country": country, + "purpose": purpose, + }, + number_create_params.NumberCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberCreateResponse, + ) + + async def retrieve( + self, + 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, + ) -> NumberRetrieveResponse: + """ + Retrieves a single phone number. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/numbers/phones/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberRetrieveResponse, + ) + + 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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> NumberListResponse: + """ + Lists phone numbers owned by the authenticated user — both BYO (`user`) and + provisioned (`mobilerun`) numbers. + + 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( + "/numbers/phones", + options=make_request_options( + 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, + }, + number_list_params.NumberListParams, + ), + ), + cast_to=NumberListResponse, + ) + + async def delete( + self, + 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, + ) -> NumberDeleteResponse: + """Cancels a Mobilerun Phone. + + The outcome depends on the number's current state: + + - If the number is still awaiting payment and no payment for it is currently + being processed, the checkout is closed immediately and the number is retired. + - If the number is on the standard paid plan and already paid and in service, + cancellation is scheduled for the end of the current billing period rather + than taking effect immediately. The number stays usable through the period + already paid for, with no partial refund. Calling this again while a + cancellation is already scheduled is a no-op that returns the same result. The + response's `state` reflects this as `cancel_scheduled` with + `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing + confirms the cancellation. + + Any other state (already refunding, a permanent billing failure, a payment + currently being processed, an included-plan number, or a non-hosted/BYO number) + returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't + owned by the caller. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._delete( + path_template("/numbers/phones/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberDeleteResponse, + ) + + async def countries( + 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, + ) -> NumberCountriesResponse: + """ + Lists the countries currently offered for a dedicated Mobilerun Phone, with live + stock status. Pass `country` as the `country` field on POST /numbers/phones. + """ + return await self._get( + "/numbers/phones/countries", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberCountriesResponse, + ) + + async def purposes( + 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, + ) -> NumberPurposesResponse: + """Lists the optional purposes currently available for a Mobilerun Phone.""" + return await self._get( + "/numbers/phones/purposes", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NumberPurposesResponse, + ) + + +class NumbersResourceWithRawResponse: + def __init__(self, numbers: NumbersResource) -> None: + self._numbers = numbers + + self.create = to_raw_response_wrapper( + numbers.create, + ) + self.retrieve = to_raw_response_wrapper( + numbers.retrieve, + ) + self.list = to_raw_response_wrapper( + numbers.list, + ) + self.delete = to_raw_response_wrapper( + numbers.delete, + ) + self.countries = to_raw_response_wrapper( + numbers.countries, + ) + self.purposes = to_raw_response_wrapper( + numbers.purposes, + ) + + @cached_property + def messages(self) -> MessagesResourceWithRawResponse: + return MessagesResourceWithRawResponse(self._numbers.messages) + + +class AsyncNumbersResourceWithRawResponse: + def __init__(self, numbers: AsyncNumbersResource) -> None: + self._numbers = numbers + + self.create = async_to_raw_response_wrapper( + numbers.create, + ) + self.retrieve = async_to_raw_response_wrapper( + numbers.retrieve, + ) + self.list = async_to_raw_response_wrapper( + numbers.list, + ) + self.delete = async_to_raw_response_wrapper( + numbers.delete, + ) + self.countries = async_to_raw_response_wrapper( + numbers.countries, + ) + self.purposes = async_to_raw_response_wrapper( + numbers.purposes, + ) + + @cached_property + def messages(self) -> AsyncMessagesResourceWithRawResponse: + return AsyncMessagesResourceWithRawResponse(self._numbers.messages) + + +class NumbersResourceWithStreamingResponse: + def __init__(self, numbers: NumbersResource) -> None: + self._numbers = numbers + + self.create = to_streamed_response_wrapper( + numbers.create, + ) + self.retrieve = to_streamed_response_wrapper( + numbers.retrieve, + ) + self.list = to_streamed_response_wrapper( + numbers.list, + ) + self.delete = to_streamed_response_wrapper( + numbers.delete, + ) + self.countries = to_streamed_response_wrapper( + numbers.countries, + ) + self.purposes = to_streamed_response_wrapper( + numbers.purposes, + ) + + @cached_property + def messages(self) -> MessagesResourceWithStreamingResponse: + return MessagesResourceWithStreamingResponse(self._numbers.messages) + + +class AsyncNumbersResourceWithStreamingResponse: + def __init__(self, numbers: AsyncNumbersResource) -> None: + self._numbers = numbers + + self.create = async_to_streamed_response_wrapper( + numbers.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + numbers.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + numbers.list, + ) + self.delete = async_to_streamed_response_wrapper( + numbers.delete, + ) + self.countries = async_to_streamed_response_wrapper( + numbers.countries, + ) + self.purposes = async_to_streamed_response_wrapper( + numbers.purposes, + ) + + @cached_property + def messages(self) -> AsyncMessagesResourceWithStreamingResponse: + return AsyncMessagesResourceWithStreamingResponse(self._numbers.messages) diff --git a/src/mobilerun_sdk/resources/store/__init__.py b/src/mobilerun_sdk/resources/store/__init__.py new file mode 100644 index 00000000..5ad832c1 --- /dev/null +++ b/src/mobilerun_sdk/resources/store/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .apps import ( + AppsResource, + AsyncAppsResource, + AppsResourceWithRawResponse, + AsyncAppsResourceWithRawResponse, + AppsResourceWithStreamingResponse, + AsyncAppsResourceWithStreamingResponse, +) +from .store import ( + StoreResource, + AsyncStoreResource, + StoreResourceWithRawResponse, + AsyncStoreResourceWithRawResponse, + StoreResourceWithStreamingResponse, + AsyncStoreResourceWithStreamingResponse, +) + +__all__ = [ + "AppsResource", + "AsyncAppsResource", + "AppsResourceWithRawResponse", + "AsyncAppsResourceWithRawResponse", + "AppsResourceWithStreamingResponse", + "AsyncAppsResourceWithStreamingResponse", + "StoreResource", + "AsyncStoreResource", + "StoreResourceWithRawResponse", + "AsyncStoreResourceWithRawResponse", + "StoreResourceWithStreamingResponse", + "AsyncStoreResourceWithStreamingResponse", +] diff --git a/src/mobilerun_sdk/resources/store/apps.py b/src/mobilerun_sdk/resources/store/apps.py new file mode 100644 index 00000000..8dc41c15 --- /dev/null +++ b/src/mobilerun_sdk/resources/store/apps.py @@ -0,0 +1,355 @@ +# 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 path_template, 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 ...types.store import app_list_params +from ..._base_client import make_request_options +from ...types.store.app_list_response import AppListResponse +from ...types.store.app_retrieve_response import AppRetrieveResponse +from ...types.store.app_add_to_workspace_response import AppAddToWorkspaceResponse + +__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 retrieve( + self, + app_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, + ) -> AppRetrieveResponse: + """ + Retrieves a single published store listing, including freshly-resolved + screenshotUrls. 404 for a draft or absent listing. + + 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 app_id: + raise ValueError(f"Expected a non-empty value for `app_id` but received {app_id!r}") + return self._get( + path_template("/store/apps/{app_id}", app_id=app_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppRetrieveResponse, + ) + + def list( + self, + *, + category: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + query: str | 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, + ) -> AppListResponse: + """ + Paginated list of published store listings, ordered featured desc, sortOrder + asc, displayName asc. + + 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( + "/store/apps", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "category": category, + "page": page, + "page_size": page_size, + "query": query, + }, + app_list_params.AppListParams, + ), + ), + cast_to=AppListResponse, + ) + + def add_to_workspace( + self, + app_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, + ) -> AppAddToWorkspaceResponse: + """ + Installs a published store app into the caller's workspace — the existing + device-install path takes over from there. 404 if no published listing exists. + + 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 app_id: + raise ValueError(f"Expected a non-empty value for `app_id` but received {app_id!r}") + return self._post( + path_template("/store/apps/{app_id}/add", app_id=app_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppAddToWorkspaceResponse, + ) + + +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 retrieve( + self, + app_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, + ) -> AppRetrieveResponse: + """ + Retrieves a single published store listing, including freshly-resolved + screenshotUrls. 404 for a draft or absent listing. + + 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 app_id: + raise ValueError(f"Expected a non-empty value for `app_id` but received {app_id!r}") + return await self._get( + path_template("/store/apps/{app_id}", app_id=app_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppRetrieveResponse, + ) + + async def list( + self, + *, + category: str | Omit = omit, + page: int | Omit = omit, + page_size: int | Omit = omit, + query: str | 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, + ) -> AppListResponse: + """ + Paginated list of published store listings, ordered featured desc, sortOrder + asc, displayName asc. + + 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( + "/store/apps", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "category": category, + "page": page, + "page_size": page_size, + "query": query, + }, + app_list_params.AppListParams, + ), + ), + cast_to=AppListResponse, + ) + + async def add_to_workspace( + self, + app_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, + ) -> AppAddToWorkspaceResponse: + """ + Installs a published store app into the caller's workspace — the existing + device-install path takes over from there. 404 if no published listing exists. + + 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 app_id: + raise ValueError(f"Expected a non-empty value for `app_id` but received {app_id!r}") + return await self._post( + path_template("/store/apps/{app_id}/add", app_id=app_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=AppAddToWorkspaceResponse, + ) + + +class AppsResourceWithRawResponse: + def __init__(self, apps: AppsResource) -> None: + self._apps = apps + + self.retrieve = to_raw_response_wrapper( + apps.retrieve, + ) + self.list = to_raw_response_wrapper( + apps.list, + ) + self.add_to_workspace = to_raw_response_wrapper( + apps.add_to_workspace, + ) + + +class AsyncAppsResourceWithRawResponse: + def __init__(self, apps: AsyncAppsResource) -> None: + self._apps = apps + + self.retrieve = async_to_raw_response_wrapper( + apps.retrieve, + ) + self.list = async_to_raw_response_wrapper( + apps.list, + ) + self.add_to_workspace = async_to_raw_response_wrapper( + apps.add_to_workspace, + ) + + +class AppsResourceWithStreamingResponse: + def __init__(self, apps: AppsResource) -> None: + self._apps = apps + + self.retrieve = to_streamed_response_wrapper( + apps.retrieve, + ) + self.list = to_streamed_response_wrapper( + apps.list, + ) + self.add_to_workspace = to_streamed_response_wrapper( + apps.add_to_workspace, + ) + + +class AsyncAppsResourceWithStreamingResponse: + def __init__(self, apps: AsyncAppsResource) -> None: + self._apps = apps + + self.retrieve = async_to_streamed_response_wrapper( + apps.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + apps.list, + ) + self.add_to_workspace = async_to_streamed_response_wrapper( + apps.add_to_workspace, + ) diff --git a/src/mobilerun_sdk/resources/store/store.py b/src/mobilerun_sdk/resources/store/store.py new file mode 100644 index 00000000..6091fbf2 --- /dev/null +++ b/src/mobilerun_sdk/resources/store/store.py @@ -0,0 +1,167 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .apps import ( + AppsResource, + AsyncAppsResource, + AppsResourceWithRawResponse, + AsyncAppsResourceWithRawResponse, + AppsResourceWithStreamingResponse, + AsyncAppsResourceWithStreamingResponse, +) +from ..._types import Body, Query, Headers, NotGiven, not_given +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.store_categories_response import StoreCategoriesResponse + +__all__ = ["StoreResource", "AsyncStoreResource"] + + +class StoreResource(SyncAPIResource): + @cached_property + def apps(self) -> AppsResource: + return AppsResource(self._client) + + @cached_property + def with_raw_response(self) -> StoreResourceWithRawResponse: + """ + 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 StoreResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> StoreResourceWithStreamingResponse: + """ + 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 StoreResourceWithStreamingResponse(self) + + def categories( + 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, + ) -> StoreCategoriesResponse: + """Distinct, sorted categories among PUBLISHED store listings. No pagination.""" + return self._get( + "/store/categories", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StoreCategoriesResponse, + ) + + +class AsyncStoreResource(AsyncAPIResource): + @cached_property + def apps(self) -> AsyncAppsResource: + return AsyncAppsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncStoreResourceWithRawResponse: + """ + 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 AsyncStoreResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncStoreResourceWithStreamingResponse: + """ + 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 AsyncStoreResourceWithStreamingResponse(self) + + async def categories( + 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, + ) -> StoreCategoriesResponse: + """Distinct, sorted categories among PUBLISHED store listings. No pagination.""" + return await self._get( + "/store/categories", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=StoreCategoriesResponse, + ) + + +class StoreResourceWithRawResponse: + def __init__(self, store: StoreResource) -> None: + self._store = store + + self.categories = to_raw_response_wrapper( + store.categories, + ) + + @cached_property + def apps(self) -> AppsResourceWithRawResponse: + return AppsResourceWithRawResponse(self._store.apps) + + +class AsyncStoreResourceWithRawResponse: + def __init__(self, store: AsyncStoreResource) -> None: + self._store = store + + self.categories = async_to_raw_response_wrapper( + store.categories, + ) + + @cached_property + def apps(self) -> AsyncAppsResourceWithRawResponse: + return AsyncAppsResourceWithRawResponse(self._store.apps) + + +class StoreResourceWithStreamingResponse: + def __init__(self, store: StoreResource) -> None: + self._store = store + + self.categories = to_streamed_response_wrapper( + store.categories, + ) + + @cached_property + def apps(self) -> AppsResourceWithStreamingResponse: + return AppsResourceWithStreamingResponse(self._store.apps) + + +class AsyncStoreResourceWithStreamingResponse: + def __init__(self, store: AsyncStoreResource) -> None: + self._store = store + + self.categories = async_to_streamed_response_wrapper( + store.categories, + ) + + @cached_property + def apps(self) -> AsyncAppsResourceWithStreamingResponse: + return AsyncAppsResourceWithStreamingResponse(self._store.apps) diff --git a/src/mobilerun_sdk/resources/tasks/screenshots.py b/src/mobilerun_sdk/resources/tasks/screenshots.py index be0c9c44..17bbbcd8 100644 --- a/src/mobilerun_sdk/resources/tasks/screenshots.py +++ b/src/mobilerun_sdk/resources/tasks/screenshots.py @@ -15,8 +15,8 @@ async_to_streamed_response_wrapper, ) from ..._base_client import make_request_options -from ...types.tasks.media_response import MediaResponse from ...types.tasks.screenshot_list_response import ScreenshotListResponse +from ...types.tasks.screenshot_retrieve_response import ScreenshotRetrieveResponse __all__ = ["ScreenshotsResource", "AsyncScreenshotsResource"] @@ -54,7 +54,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MediaResponse: + ) -> ScreenshotRetrieveResponse: """ Get a specific screenshot by index. @@ -74,7 +74,7 @@ def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MediaResponse, + cast_to=ScreenshotRetrieveResponse, ) def list( @@ -144,7 +144,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MediaResponse: + ) -> ScreenshotRetrieveResponse: """ Get a specific screenshot by index. @@ -164,7 +164,7 @@ async def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MediaResponse, + cast_to=ScreenshotRetrieveResponse, ) async def list( diff --git a/src/mobilerun_sdk/resources/tasks/tasks.py b/src/mobilerun_sdk/resources/tasks/tasks.py index 2b01fa86..e73ca6bb 100644 --- a/src/mobilerun_sdk/resources/tasks/tasks.py +++ b/src/mobilerun_sdk/resources/tasks/tasks.py @@ -7,7 +7,7 @@ import httpx -from ...types import TaskStatus, task_run_params, task_list_params, task_run_streamed_params, task_send_message_params +from ...types import task_run_params, task_list_params, task_run_streamed_params, task_send_message_params from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property @@ -35,13 +35,11 @@ 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 -from ...types.package_credentials_param import PackageCredentialsParam from ...types.task_send_message_response import TaskSendMessageResponse from ...types.task_get_trajectory_response import TaskGetTrajectoryResponse @@ -123,7 +121,8 @@ def list( page: int | Omit = omit, page_size: int | Omit = omit, query: Optional[str] | Omit = omit, - status: Optional[TaskStatus] | Omit = omit, + status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] + | 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, @@ -282,7 +281,7 @@ def run( agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, - credentials: Iterable[PackageCredentialsParam] | Omit = omit, + credentials: Iterable[task_run_params.Credential] | Omit = omit, display_id: int | Omit = omit, execution_timeout: int | Omit = omit, files: SequenceNotStr[str] | Omit = omit, @@ -371,7 +370,7 @@ def run_streamed( agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, - credentials: Iterable[PackageCredentialsParam] | Omit = omit, + credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit, display_id: int | Omit = omit, execution_timeout: int | Omit = omit, files: SequenceNotStr[str] | Omit = omit, @@ -598,7 +597,8 @@ async def list( page: int | Omit = omit, page_size: int | Omit = omit, query: Optional[str] | Omit = omit, - status: Optional[TaskStatus] | Omit = omit, + status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] + | 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, @@ -757,7 +757,7 @@ async def run( agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, - credentials: Iterable[PackageCredentialsParam] | Omit = omit, + credentials: Iterable[task_run_params.Credential] | Omit = omit, display_id: int | Omit = omit, execution_timeout: int | Omit = omit, files: SequenceNotStr[str] | Omit = omit, @@ -846,7 +846,7 @@ async def run_streamed( agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, - credentials: Iterable[PackageCredentialsParam] | Omit = omit, + credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit, display_id: int | Omit = omit, execution_timeout: int | Omit = omit, files: SequenceNotStr[str] | Omit = omit, diff --git a/src/mobilerun_sdk/resources/tasks/ui_states.py b/src/mobilerun_sdk/resources/tasks/ui_states.py index 35677244..52aeb6bd 100644 --- a/src/mobilerun_sdk/resources/tasks/ui_states.py +++ b/src/mobilerun_sdk/resources/tasks/ui_states.py @@ -15,8 +15,8 @@ async_to_streamed_response_wrapper, ) from ..._base_client import make_request_options -from ...types.tasks.media_response import MediaResponse from ...types.tasks.ui_state_list_response import UiStateListResponse +from ...types.tasks.ui_state_retrieve_response import UiStateRetrieveResponse __all__ = ["UiStatesResource", "AsyncUiStatesResource"] @@ -54,7 +54,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MediaResponse: + ) -> UiStateRetrieveResponse: """ Get a specific UI state by index. @@ -74,7 +74,7 @@ def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MediaResponse, + cast_to=UiStateRetrieveResponse, ) def list( @@ -144,7 +144,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> MediaResponse: + ) -> UiStateRetrieveResponse: """ Get a specific UI state by index. @@ -164,7 +164,7 @@ async def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=MediaResponse, + cast_to=UiStateRetrieveResponse, ) async def list( diff --git a/src/mobilerun_sdk/resources/workflows/executions.py b/src/mobilerun_sdk/resources/workflows/executions.py index c8a4840c..cb7e5a19 100644 --- a/src/mobilerun_sdk/resources/workflows/executions.py +++ b/src/mobilerun_sdk/resources/workflows/executions.py @@ -20,6 +20,7 @@ from ..._base_client import make_request_options from ...types.workflows import execution_list_params, execution_get_metrics_params from ...types.workflows.execution_list_response import ExecutionListResponse +from ...types.workflows.execution_abort_response import ExecutionAbortResponse from ...types.workflows.execution_retrieve_response import ExecutionRetrieveResponse from ...types.workflows.execution_get_metrics_response import ExecutionGetMetricsResponse @@ -141,6 +142,40 @@ def list( cast_to=ExecutionListResponse, ) + def abort( + self, + execution_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, + ) -> ExecutionAbortResponse: + """ + Signals the worker to stop the execution between steps and marks it cancelled. + Idempotent-ish: already-terminal executions return 409. + + 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 execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return self._post( + path_template("/executions/{execution_id}/abort", execution_id=execution_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExecutionAbortResponse, + ) + def get_metrics( self, *, @@ -305,6 +340,40 @@ async def list( cast_to=ExecutionListResponse, ) + async def abort( + self, + execution_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, + ) -> ExecutionAbortResponse: + """ + Signals the worker to stop the execution between steps and marks it cancelled. + Idempotent-ish: already-terminal executions return 409. + + 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 execution_id: + raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}") + return await self._post( + path_template("/executions/{execution_id}/abort", execution_id=execution_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExecutionAbortResponse, + ) + async def get_metrics( self, *, @@ -364,6 +433,9 @@ def __init__(self, executions: ExecutionsResource) -> None: self.list = to_raw_response_wrapper( executions.list, ) + self.abort = to_raw_response_wrapper( + executions.abort, + ) self.get_metrics = to_raw_response_wrapper( executions.get_metrics, ) @@ -379,6 +451,9 @@ def __init__(self, executions: AsyncExecutionsResource) -> None: self.list = async_to_raw_response_wrapper( executions.list, ) + self.abort = async_to_raw_response_wrapper( + executions.abort, + ) self.get_metrics = async_to_raw_response_wrapper( executions.get_metrics, ) @@ -394,6 +469,9 @@ def __init__(self, executions: ExecutionsResource) -> None: self.list = to_streamed_response_wrapper( executions.list, ) + self.abort = to_streamed_response_wrapper( + executions.abort, + ) self.get_metrics = to_streamed_response_wrapper( executions.get_metrics, ) @@ -409,6 +487,9 @@ def __init__(self, executions: AsyncExecutionsResource) -> None: self.list = async_to_streamed_response_wrapper( executions.list, ) + self.abort = async_to_streamed_response_wrapper( + executions.abort, + ) self.get_metrics = async_to_streamed_response_wrapper( executions.get_metrics, ) diff --git a/src/mobilerun_sdk/resources/workflows/flows/actions.py b/src/mobilerun_sdk/resources/workflows/flows/actions.py index cec5aa4b..0fd2150d 100644 --- a/src/mobilerun_sdk/resources/workflows/flows/actions.py +++ b/src/mobilerun_sdk/resources/workflows/flows/actions.py @@ -20,9 +20,7 @@ from ....types.workflows.flows import action_add_params, action_replace_params from ....types.workflows.flows.action_add_response import ActionAddResponse from ....types.workflows.flows.action_list_response import ActionListResponse -from ....types.workflows.flow_action_overrides_param import FlowActionOverridesParam from ....types.workflows.flows.action_remove_response import ActionRemoveResponse -from ....types.workflows.flow_child_action_input_param import FlowChildActionInputParam from ....types.workflows.flows.action_replace_response import ActionReplaceResponse __all__ = ["ActionsResource", "AsyncActionsResource"] @@ -88,10 +86,10 @@ def add( *, action_id: str, position: int, - children: Iterable[FlowChildActionInputParam] | Omit = omit, + children: Iterable[action_add_params.Child] | Omit = omit, continue_on_error: bool | Omit = omit, name_override: str | Omit = omit, - overrides: Optional[FlowActionOverridesParam] | Omit = omit, + overrides: Optional[action_add_params.Overrides] | Omit = omit, parent_flow_action_id: Optional[str] | 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. @@ -274,10 +272,10 @@ async def add( *, action_id: str, position: int, - children: Iterable[FlowChildActionInputParam] | Omit = omit, + children: Iterable[action_add_params.Child] | Omit = omit, continue_on_error: bool | Omit = omit, name_override: str | Omit = omit, - overrides: Optional[FlowActionOverridesParam] | Omit = omit, + overrides: Optional[action_add_params.Overrides] | Omit = omit, parent_flow_action_id: Optional[str] | 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_sdk/resources/workflows/flows/flows.py b/src/mobilerun_sdk/resources/workflows/flows/flows.py index c9c2f371..79277a29 100644 --- a/src/mobilerun_sdk/resources/workflows/flows/flows.py +++ b/src/mobilerun_sdk/resources/workflows/flows/flows.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Dict, List, Iterable, Optional from typing_extensions import Literal import httpx @@ -26,14 +26,22 @@ async_to_streamed_response_wrapper, ) from ...._base_client import make_request_options -from ....types.workflows import flow_list_params, flow_clone_params, flow_create_params, flow_update_params +from ....types.workflows import ( + flow_list_params, + flow_clone_params, + flow_create_params, + flow_update_params, + flow_dry_run_params, +) from ....types.workflows.flow_list_response import FlowListResponse from ....types.workflows.flow_clone_response import FlowCloneResponse from ....types.workflows.flow_create_response import FlowCreateResponse from ....types.workflows.flow_delete_response import FlowDeleteResponse from ....types.workflows.flow_update_response import FlowUpdateResponse +from ....types.workflows.flow_dry_run_response import FlowDryRunResponse from ....types.workflows.flow_unblock_response import FlowUnblockResponse from ....types.workflows.flow_retrieve_response import FlowRetrieveResponse +from ....types.workflows.flow_list_repairs_response import FlowListRepairsResponse __all__ = ["FlowsResource", "AsyncFlowsResource"] @@ -374,6 +382,87 @@ def clone( cast_to=FlowCloneResponse, ) + def dry_run( + self, + flow_id: str, + *, + payload: Dict[str, object] | 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, + ) -> FlowDryRunResponse: + """ + Simulate this flow firing without storing events, enqueuing jobs, or consuming + cooldown/rate-limit slots. + + Works for every trigger activation type: + + - `event`: validates the payload against the event catalog schema and evaluates + the trigger conditions. + - `custom`: validates the payload against the custom payload schema (conditions + do not apply). + - `schedule`: ignores the payload and reports the next fire time. + + The response reports `wouldFire` — whether the flow would actually run right now + — alongside the gates that decide it (enabled, device attached, blocked, + cooldown). `rateLimited` is informational and is not folded into `wouldFire`. + + 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 flow_id: + raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}") + return self._post( + path_template("/flows/{flow_id}/dry-run", flow_id=flow_id), + body=maybe_transform({"payload": payload}, flow_dry_run_params.FlowDryRunParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FlowDryRunResponse, + ) + + def list_repairs( + self, + flow_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, + ) -> FlowListRepairsResponse: + """ + List self-healing repair episodes + + 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 flow_id: + raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}") + return self._get( + path_template("/flows/{flow_id}/repairs", flow_id=flow_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FlowListRepairsResponse, + ) + def unblock( self, flow_id: str, @@ -746,6 +835,87 @@ async def clone( cast_to=FlowCloneResponse, ) + async def dry_run( + self, + flow_id: str, + *, + payload: Dict[str, object] | 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, + ) -> FlowDryRunResponse: + """ + Simulate this flow firing without storing events, enqueuing jobs, or consuming + cooldown/rate-limit slots. + + Works for every trigger activation type: + + - `event`: validates the payload against the event catalog schema and evaluates + the trigger conditions. + - `custom`: validates the payload against the custom payload schema (conditions + do not apply). + - `schedule`: ignores the payload and reports the next fire time. + + The response reports `wouldFire` — whether the flow would actually run right now + — alongside the gates that decide it (enabled, device attached, blocked, + cooldown). `rateLimited` is informational and is not folded into `wouldFire`. + + 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 flow_id: + raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}") + return await self._post( + path_template("/flows/{flow_id}/dry-run", flow_id=flow_id), + body=await async_maybe_transform({"payload": payload}, flow_dry_run_params.FlowDryRunParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FlowDryRunResponse, + ) + + async def list_repairs( + self, + flow_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, + ) -> FlowListRepairsResponse: + """ + List self-healing repair episodes + + 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 flow_id: + raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}") + return await self._get( + path_template("/flows/{flow_id}/repairs", flow_id=flow_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=FlowListRepairsResponse, + ) + async def unblock( self, flow_id: str, @@ -804,6 +974,12 @@ def __init__(self, flows: FlowsResource) -> None: self.clone = to_raw_response_wrapper( flows.clone, ) + self.dry_run = to_raw_response_wrapper( + flows.dry_run, + ) + self.list_repairs = to_raw_response_wrapper( + flows.list_repairs, + ) self.unblock = to_raw_response_wrapper( flows.unblock, ) @@ -835,6 +1011,12 @@ def __init__(self, flows: AsyncFlowsResource) -> None: self.clone = async_to_raw_response_wrapper( flows.clone, ) + self.dry_run = async_to_raw_response_wrapper( + flows.dry_run, + ) + self.list_repairs = async_to_raw_response_wrapper( + flows.list_repairs, + ) self.unblock = async_to_raw_response_wrapper( flows.unblock, ) @@ -866,6 +1048,12 @@ def __init__(self, flows: FlowsResource) -> None: self.clone = to_streamed_response_wrapper( flows.clone, ) + self.dry_run = to_streamed_response_wrapper( + flows.dry_run, + ) + self.list_repairs = to_streamed_response_wrapper( + flows.list_repairs, + ) self.unblock = to_streamed_response_wrapper( flows.unblock, ) @@ -897,6 +1085,12 @@ def __init__(self, flows: AsyncFlowsResource) -> None: self.clone = async_to_streamed_response_wrapper( flows.clone, ) + self.dry_run = async_to_streamed_response_wrapper( + flows.dry_run, + ) + self.list_repairs = async_to_streamed_response_wrapper( + flows.list_repairs, + ) self.unblock = async_to_streamed_response_wrapper( flows.unblock, ) diff --git a/src/mobilerun_sdk/resources/workflows/triggers.py b/src/mobilerun_sdk/resources/workflows/triggers.py index ea8794ee..d569d1eb 100644 --- a/src/mobilerun_sdk/resources/workflows/triggers.py +++ b/src/mobilerun_sdk/resources/workflows/triggers.py @@ -144,12 +144,12 @@ def update( trigger_id: str, *, activation: Literal["event", "schedule", "custom"] | Omit = omit, - conditions: trigger_update_params.Conditions | Omit = omit, - custom_payload_schema: Dict[str, object] | Omit = omit, + conditions: Optional[trigger_update_params.Conditions] | Omit = omit, + custom_payload_schema: Optional[Dict[str, object]] | Omit = omit, description: str | Omit = omit, event_type: str | Omit = omit, name: str | Omit = omit, - schedule_rule: trigger_update_params.ScheduleRule | Omit = omit, + schedule_rule: Optional[trigger_update_params.ScheduleRule] | Omit = omit, timezone: Optional[str] | 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. @@ -165,6 +165,8 @@ def update( trigger does not exist. Args: + custom_payload_schema: Optional JSON Schema for validating payloads sent to this custom trigger + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -455,12 +457,12 @@ async def update( trigger_id: str, *, activation: Literal["event", "schedule", "custom"] | Omit = omit, - conditions: trigger_update_params.Conditions | Omit = omit, - custom_payload_schema: Dict[str, object] | Omit = omit, + conditions: Optional[trigger_update_params.Conditions] | Omit = omit, + custom_payload_schema: Optional[Dict[str, object]] | Omit = omit, description: str | Omit = omit, event_type: str | Omit = omit, name: str | Omit = omit, - schedule_rule: trigger_update_params.ScheduleRule | Omit = omit, + schedule_rule: Optional[trigger_update_params.ScheduleRule] | Omit = omit, timezone: Optional[str] | 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. @@ -476,6 +478,8 @@ async def update( trigger does not exist. Args: + custom_payload_schema: Optional JSON Schema for validating payloads sent to this custom trigger + extra_headers: Send extra headers extra_query: Add additional query parameters to the request diff --git a/src/mobilerun_sdk/types/__init__.py b/src/mobilerun_sdk/types/__init__.py index a9079d33..f634c2c1 100644 --- a/src/mobilerun_sdk/types/__init__.py +++ b/src/mobilerun_sdk/types/__init__.py @@ -4,12 +4,8 @@ from . import devices from .. import _compat -from .flow import Flow as Flow -from .task import Task as Task -from .device import Device as Device from .shared import ( Meta as Meta, - Socks5 as Socks5, Location as Location, DeviceSpec as DeviceSpec, Pagination as Pagination, @@ -17,23 +13,29 @@ PermissionSet as PermissionSet, PaginationMeta as PaginationMeta, DeviceIdentifiers as DeviceIdentifiers, + Socks5ProxyConfig as Socks5ProxyConfig, ) -from .task_status import TaskStatus as TaskStatus -from .proxy_config import ProxyConfig as ProxyConfig -from .usage_result import UsageResult as UsageResult from .app_list_params import AppListParams as AppListParams from .task_run_params import TaskRunParams as TaskRunParams +from .esim_list_params import EsimListParams as EsimListParams from .task_list_params import TaskListParams as TaskListParams from .app_list_response import AppListResponse as AppListResponse from .proxy_list_params import ProxyListParams as ProxyListParams from .task_run_response import TaskRunResponse as TaskRunResponse from .device_list_params import DeviceListParams as DeviceListParams +from .esim_create_params import EsimCreateParams as EsimCreateParams +from .esim_import_params import EsimImportParams as EsimImportParams +from .esim_list_response import EsimListResponse as EsimListResponse +from .esim_update_params import EsimUpdateParams as EsimUpdateParams +from .number_list_params import NumberListParams as NumberListParams from .task_list_response import TaskListResponse as TaskListResponse from .task_stop_response import TaskStopResponse as TaskStopResponse +from .agent_list_response import AgentListResponse as AgentListResponse from .app_delete_response import AppDeleteResponse as AppDeleteResponse from .carrier_list_params import CarrierListParams as CarrierListParams +from .esim_install_params import EsimInstallParams as EsimInstallParams +from .message_list_params import MessageListParams as MessageListParams from .model_list_response import ModelListResponse as ModelListResponse -from .package_credentials import PackageCredentials as PackageCredentials from .profile_list_params import ProfileListParams as ProfileListParams from .proxy_create_params import ProxyCreateParams as ProxyCreateParams from .proxy_list_response import ProxyListResponse as ProxyListResponse @@ -42,12 +44,20 @@ from .webhook_list_params import WebhookListParams as WebhookListParams from .device_create_params import DeviceCreateParams as DeviceCreateParams from .device_list_response import DeviceListResponse as DeviceListResponse +from .esim_create_response import EsimCreateResponse as EsimCreateResponse +from .esim_import_response import EsimImportResponse as EsimImportResponse +from .esim_update_response import EsimUpdateResponse as EsimUpdateResponse +from .number_create_params import NumberCreateParams as NumberCreateParams +from .number_list_response import NumberListResponse as NumberListResponse +from .app_event_list_params import AppEventListParams as AppEventListParams from .app_retrieve_response import AppRetrieveResponse as AppRetrieveResponse from .carrier_create_params import CarrierCreateParams as CarrierCreateParams from .carrier_list_response import CarrierListResponse as CarrierListResponse from .carrier_lookup_params import CarrierLookupParams as CarrierLookupParams from .carrier_update_params import CarrierUpdateParams as CarrierUpdateParams from .device_count_response import DeviceCountResponse as DeviceCountResponse +from .esim_install_response import EsimInstallResponse as EsimInstallResponse +from .message_list_response import MessageListResponse as MessageListResponse from .profile_create_params import ProfileCreateParams as ProfileCreateParams from .profile_list_response import ProfileListResponse as ProfileListResponse from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams @@ -59,8 +69,15 @@ from .webhook_list_response import WebhookListResponse as WebhookListResponse from .webhook_update_params import WebhookUpdateParams as WebhookUpdateParams from .credential_list_params import CredentialListParams as CredentialListParams +from .device_create_response import DeviceCreateResponse as DeviceCreateResponse from .device_set_name_params import DeviceSetNameParams as DeviceSetNameParams +from .esim_capacity_response import EsimCapacityResponse as EsimCapacityResponse +from .esim_retrieve_response import EsimRetrieveResponse as EsimRetrieveResponse +from .esim_selector_response import EsimSelectorResponse as EsimSelectorResponse +from .number_create_response import NumberCreateResponse as NumberCreateResponse +from .number_delete_response import NumberDeleteResponse as NumberDeleteResponse from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse +from .app_event_list_response import AppEventListResponse as AppEventListResponse from .carrier_create_response import CarrierCreateResponse as CarrierCreateResponse from .carrier_delete_response import CarrierDeleteResponse as CarrierDeleteResponse from .carrier_lookup_response import CarrierLookupResponse as CarrierLookupResponse @@ -74,23 +91,46 @@ from .webhook_update_response import WebhookUpdateResponse as WebhookUpdateResponse from .app_mark_failed_response import AppMarkFailedResponse as AppMarkFailedResponse from .credential_list_response import CredentialListResponse as CredentialListResponse +from .device_retrieve_response import DeviceRetrieveResponse as DeviceRetrieveResponse +from .device_set_name_response import DeviceSetNameResponse as DeviceSetNameResponse +from .number_purposes_response import NumberPurposesResponse as NumberPurposesResponse +from .number_retrieve_response import NumberRetrieveResponse as NumberRetrieveResponse from .task_get_status_response import TaskGetStatusResponse as TaskGetStatusResponse from .task_run_streamed_params import TaskRunStreamedParams as TaskRunStreamedParams from .task_send_message_params import TaskSendMessageParams as TaskSendMessageParams from .carrier_retrieve_response import CarrierRetrieveResponse as CarrierRetrieveResponse -from .package_credentials_param import PackageCredentialsParam as PackageCredentialsParam +from .number_countries_response import NumberCountriesResponse as NumberCountriesResponse from .profile_retrieve_response import ProfileRetrieveResponse as ProfileRetrieveResponse +from .store_categories_response import StoreCategoriesResponse as StoreCategoriesResponse from .webhook_retrieve_response import WebhookRetrieveResponse as WebhookRetrieveResponse from .app_list_versions_response import AppListVersionsResponse as AppListVersionsResponse +from .app_storage_usage_response import AppStorageUsageResponse as AppStorageUsageResponse +from .device_wait_ready_response import DeviceWaitReadyResponse as DeviceWaitReadyResponse from .task_send_message_response import TaskSendMessageResponse as TaskSendMessageResponse from .app_confirm_upload_response import AppConfirmUploadResponse as AppConfirmUploadResponse +from .app_event_retrieve_response import AppEventRetrieveResponse as AppEventRetrieveResponse from .device_fingerprint_response import DeviceFingerprintResponse as DeviceFingerprintResponse +from .esim_install_status_response import EsimInstallStatusResponse as EsimInstallStatusResponse from .task_get_trajectory_response import TaskGetTrajectoryResponse as TaskGetTrajectoryResponse from .webhook_event_types_response import WebhookEventTypesResponse as WebhookEventTypesResponse +from .esim_confirm_payment_response import EsimConfirmPaymentResponse as EsimConfirmPaymentResponse +from .notification_catalog_response import NotificationCatalogResponse as NotificationCatalogResponse from .webhook_rotate_secret_response import WebhookRotateSecretResponse as WebhookRotateSecretResponse from .webhook_test_delivery_response import WebhookTestDeliveryResponse as WebhookTestDeliveryResponse from .app_create_signed_upload_url_params import AppCreateSignedUploadURLParams as AppCreateSignedUploadURLParams from .app_create_signed_upload_url_response import AppCreateSignedUploadURLResponse as AppCreateSignedUploadURLResponse +from .device_retrieve_capabilities_response import ( + DeviceRetrieveCapabilitiesResponse as DeviceRetrieveCapabilitiesResponse, +) +from .notification_get_preferences_response import ( + NotificationGetPreferencesResponse as NotificationGetPreferencesResponse, +) +from .notification_update_preferences_params import ( + NotificationUpdatePreferencesParams as NotificationUpdatePreferencesParams, +) +from .notification_update_preferences_response import ( + NotificationUpdatePreferencesResponse as NotificationUpdatePreferencesResponse, +) # Rebuild cyclical models only after all modules are imported. # This ensures that, when building the deferred (due to cyclical references) model schema, diff --git a/src/mobilerun_sdk/types/agent_list_response.py b/src/mobilerun_sdk/types/agent_list_response.py new file mode 100644 index 00000000..fc366d60 --- /dev/null +++ b/src/mobilerun_sdk/types/agent_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 typing_extensions import TypeAlias + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["AgentListResponse", "AgentListResponseItem"] + + +class AgentListResponseItem(BaseModel): + id: int + + description: Optional[str] = None + + icon: str + + llm_model: str = FieldInfo(alias="llmModel") + + max_steps: int = FieldInfo(alias="maxSteps") + + name: str + + reasoning: bool + + subagent_model: Optional[str] = FieldInfo(alias="subagentModel", default=None) + + vision: bool + + +AgentListResponse: TypeAlias = List[AgentListResponseItem] diff --git a/src/mobilerun_sdk/types/app_event_list_params.py b/src/mobilerun_sdk/types/app_event_list_params.py new file mode 100644 index 00000000..4bae2116 --- /dev/null +++ b/src/mobilerun_sdk/types/app_event_list_params.py @@ -0,0 +1,26 @@ +# 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__ = ["AppEventListParams"] + + +class AppEventListParams(TypedDict, total=False): + device_id: Annotated[str, PropertyInfo(alias="deviceId")] + + event_type: Annotated[str, PropertyInfo(alias="eventType")] + + from_: Annotated[Optional[str], PropertyInfo(alias="from")] + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + source: Literal["app", "system", "device", "webhook"] + + to: Optional[str] diff --git a/src/mobilerun_sdk/types/app_event_list_response.py b/src/mobilerun_sdk/types/app_event_list_response.py new file mode 100644 index 00000000..97b2e452 --- /dev/null +++ b/src/mobilerun_sdk/types/app_event_list_response.py @@ -0,0 +1,42 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .shared.pagination import Pagination + +__all__ = ["AppEventListResponse", "Item"] + + +class Item(BaseModel): + id: str + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + event_type: str = FieldInfo(alias="eventType") + + occurred_at: Optional[str] = FieldInfo(alias="occurredAt", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + payload: Dict[str, object] + + raw_event_id: Optional[str] = FieldInfo(alias="rawEventId", default=None) + + source: Literal["app", "system", "device", "webhook"] + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + +class AppEventListResponse(BaseModel): + items: List[Item] + + pagination: Pagination diff --git a/src/mobilerun_sdk/types/app_event_retrieve_response.py b/src/mobilerun_sdk/types/app_event_retrieve_response.py new file mode 100644 index 00000000..15666c6e --- /dev/null +++ b/src/mobilerun_sdk/types/app_event_retrieve_response.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["AppEventRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + event_type: str = FieldInfo(alias="eventType") + + occurred_at: Optional[str] = FieldInfo(alias="occurredAt", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + payload: Dict[str, object] + + raw_event_id: Optional[str] = FieldInfo(alias="rawEventId", default=None) + + source: Literal["app", "system", "device", "webhook"] + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + +class AppEventRetrieveResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/app_events/__init__.py b/src/mobilerun_sdk/types/app_events/__init__.py new file mode 100644 index 00000000..b44f4116 --- /dev/null +++ b/src/mobilerun_sdk/types/app_events/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .catalog_list_response import CatalogListResponse as CatalogListResponse +from .catalog_retrieve_response import CatalogRetrieveResponse as CatalogRetrieveResponse diff --git a/src/mobilerun_sdk/types/app_events/catalog_list_response.py b/src/mobilerun_sdk/types/app_events/catalog_list_response.py new file mode 100644 index 00000000..1ffcfb01 --- /dev/null +++ b/src/mobilerun_sdk/types/app_events/catalog_list_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["CatalogListResponse", "Data", "DataPayloadSchema"] + + +class DataPayloadSchema(BaseModel): + description: str + + name: str + + type: Literal["string", "number", "boolean", "object", "array"] + + example: Optional[object] = None + + +class Data(BaseModel): + app_event_type: str = FieldInfo(alias="appEventType") + + app_name: str = FieldInfo(alias="appName") + + category: Literal["app", "system", "device", "webhook"] + + label: str + + package_name: Optional[str] = FieldInfo(alias="packageName", default=None) + + payload_schema: List[DataPayloadSchema] = FieldInfo(alias="payloadSchema") + + source_event_type: str = FieldInfo(alias="sourceEventType") + + +class CatalogListResponse(BaseModel): + data: List[Data] diff --git a/src/mobilerun_sdk/types/app_events/catalog_retrieve_response.py b/src/mobilerun_sdk/types/app_events/catalog_retrieve_response.py new file mode 100644 index 00000000..2dc7c252 --- /dev/null +++ b/src/mobilerun_sdk/types/app_events/catalog_retrieve_response.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["CatalogRetrieveResponse", "Data", "DataPayloadSchema"] + + +class DataPayloadSchema(BaseModel): + description: str + + name: str + + type: Literal["string", "number", "boolean", "object", "array"] + + example: Optional[object] = None + + +class Data(BaseModel): + app_event_type: str = FieldInfo(alias="appEventType") + + app_name: str = FieldInfo(alias="appName") + + category: Literal["app", "system", "device", "webhook"] + + label: str + + package_name: Optional[str] = FieldInfo(alias="packageName", default=None) + + payload_schema: List[DataPayloadSchema] = FieldInfo(alias="payloadSchema") + + source_event_type: str = FieldInfo(alias="sourceEventType") + + +class CatalogRetrieveResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/app_storage_usage_response.py b/src/mobilerun_sdk/types/app_storage_usage_response.py new file mode 100644 index 00000000..f1c225ec --- /dev/null +++ b/src/mobilerun_sdk/types/app_storage_usage_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["AppStorageUsageResponse", "Data"] + + +class Data(BaseModel): + available_bytes: float = FieldInfo(alias="availableBytes") + """Remaining bytes — the reliable maximum size for the next upload. + + Advisory snapshot: the quota is enforced under a lock at confirm, so concurrent + uploads may reduce actual headroom. + """ + + quota_bytes: float = FieldInfo(alias="quotaBytes") + """Total storage allowance for the user, in bytes""" + + used_bytes: float = FieldInfo(alias="usedBytes") + """Bytes currently consumed across all of the user’s app versions""" + + +class AppStorageUsageResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/credential_list_response.py b/src/mobilerun_sdk/types/credential_list_response.py index 0721b2b3..38da9557 100644 --- a/src/mobilerun_sdk/types/credential_list_response.py +++ b/src/mobilerun_sdk/types/credential_list_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo from .._models import BaseModel from .shared.pagination import Pagination -from .credentials.packages.credential import Credential -__all__ = ["CredentialListResponse"] +__all__ = ["CredentialListResponse", "Item", "ItemField"] + + +class ItemField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Item(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[ItemField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class CredentialListResponse(BaseModel): - items: List[Credential] + items: List[Item] pagination: Pagination diff --git a/src/mobilerun_sdk/types/credentials/__init__.py b/src/mobilerun_sdk/types/credentials/__init__.py index d2b799c0..9d64da9b 100644 --- a/src/mobilerun_sdk/types/credentials/__init__.py +++ b/src/mobilerun_sdk/types/credentials/__init__.py @@ -5,3 +5,4 @@ from .package_create_params import PackageCreateParams as PackageCreateParams from .package_list_response import PackageListResponse as PackageListResponse from .package_create_response import PackageCreateResponse as PackageCreateResponse +from .package_list_all_response import PackageListAllResponse as PackageListAllResponse diff --git a/src/mobilerun_sdk/types/package_credentials.py b/src/mobilerun_sdk/types/credentials/package_list_all_response.py similarity index 55% rename from src/mobilerun_sdk/types/package_credentials.py rename to src/mobilerun_sdk/types/credentials/package_list_all_response.py index ccf32863..61d09086 100644 --- a/src/mobilerun_sdk/types/package_credentials.py +++ b/src/mobilerun_sdk/types/credentials/package_list_all_response.py @@ -4,12 +4,14 @@ from pydantic import Field as FieldInfo -from .._models import BaseModel +from ..._models import BaseModel -__all__ = ["PackageCredentials"] +__all__ = ["PackageListAllResponse", "Data"] -class PackageCredentials(BaseModel): - credential_names: List[str] = FieldInfo(alias="credentialNames") - +class Data(BaseModel): package_name: str = FieldInfo(alias="packageName") + + +class PackageListAllResponse(BaseModel): + data: List[Data] diff --git a/src/mobilerun_sdk/types/credentials/package_list_response.py b/src/mobilerun_sdk/types/credentials/package_list_response.py index c9567e1e..092a1df9 100644 --- a/src/mobilerun_sdk/types/credentials/package_list_response.py +++ b/src/mobilerun_sdk/types/credentials/package_list_response.py @@ -1,12 +1,42 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo from ..._models import BaseModel -from .packages.credential import Credential -__all__ = ["PackageListResponse"] +__all__ = ["PackageListResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class PackageListResponse(BaseModel): - data: List[Credential] + data: List[Data] diff --git a/src/mobilerun_sdk/types/credentials/packages/__init__.py b/src/mobilerun_sdk/types/credentials/packages/__init__.py index a3bddb02..e5fc9088 100644 --- a/src/mobilerun_sdk/types/credentials/packages/__init__.py +++ b/src/mobilerun_sdk/types/credentials/packages/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations -from .credential import Credential as Credential from .credential_create_params import CredentialCreateParams as CredentialCreateParams from .credential_create_response import CredentialCreateResponse as CredentialCreateResponse from .credential_delete_response import CredentialDeleteResponse as CredentialDeleteResponse diff --git a/src/mobilerun_sdk/types/credentials/packages/credential.py b/src/mobilerun_sdk/types/credentials/packages/credential.py deleted file mode 100644 index 5bda2ccd..00000000 --- a/src/mobilerun_sdk/types/credentials/packages/credential.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["Credential", "Field"] - - -class Field(BaseModel): - field_type: Literal[ - "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" - ] = FieldInfo(alias="fieldType") - - value: str - - -class Credential(BaseModel): - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - credential_name: str = FieldInfo(alias="credentialName") - - fields: List[Field] - - owner_id: str = FieldInfo(alias="ownerId") - - package_name: str = FieldInfo(alias="packageName") - - secret_path: str = FieldInfo(alias="secretPath") - - user_id: Optional[str] = FieldInfo(alias="userId", default=None) - """Deprecated: use createdBy (same value — the creating actor). - - Null for credentials created before rollout. - """ diff --git a/src/mobilerun_sdk/types/credentials/packages/credential_create_response.py b/src/mobilerun_sdk/types/credentials/packages/credential_create_response.py index 56749ca9..8cce5a94 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credential_create_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credential_create_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ...._models import BaseModel -from .credential import Credential -__all__ = ["CredentialCreateResponse"] +__all__ = ["CredentialCreateResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class CredentialCreateResponse(BaseModel): - data: Credential + data: Data message: str diff --git a/src/mobilerun_sdk/types/credentials/packages/credential_delete_response.py b/src/mobilerun_sdk/types/credentials/packages/credential_delete_response.py index 9fc9bf46..f5528ed9 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credential_delete_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credential_delete_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ...._models import BaseModel -from .credential import Credential -__all__ = ["CredentialDeleteResponse"] +__all__ = ["CredentialDeleteResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class CredentialDeleteResponse(BaseModel): - data: Credential + data: Data message: str diff --git a/src/mobilerun_sdk/types/credentials/packages/credential_retrieve_response.py b/src/mobilerun_sdk/types/credentials/packages/credential_retrieve_response.py index ea546ccf..11cc259b 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credential_retrieve_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credential_retrieve_response.py @@ -1,10 +1,42 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ...._models import BaseModel -from .credential import Credential -__all__ = ["CredentialRetrieveResponse"] +__all__ = ["CredentialRetrieveResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class CredentialRetrieveResponse(BaseModel): - data: Credential + data: Data diff --git a/src/mobilerun_sdk/types/credentials/packages/credentials/field_create_response.py b/src/mobilerun_sdk/types/credentials/packages/credentials/field_create_response.py index 2d7f2d0d..c3e3a102 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credentials/field_create_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credentials/field_create_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ....._models import BaseModel -from ..credential import Credential -__all__ = ["FieldCreateResponse"] +__all__ = ["FieldCreateResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class FieldCreateResponse(BaseModel): - data: Credential + data: Data message: str diff --git a/src/mobilerun_sdk/types/credentials/packages/credentials/field_delete_response.py b/src/mobilerun_sdk/types/credentials/packages/credentials/field_delete_response.py index 67e99f83..25d64be0 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credentials/field_delete_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credentials/field_delete_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ....._models import BaseModel -from ..credential import Credential -__all__ = ["FieldDeleteResponse"] +__all__ = ["FieldDeleteResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class FieldDeleteResponse(BaseModel): - data: Credential + data: Data message: str diff --git a/src/mobilerun_sdk/types/credentials/packages/credentials/field_update_response.py b/src/mobilerun_sdk/types/credentials/packages/credentials/field_update_response.py index 8676ce30..4a37ce71 100644 --- a/src/mobilerun_sdk/types/credentials/packages/credentials/field_update_response.py +++ b/src/mobilerun_sdk/types/credentials/packages/credentials/field_update_response.py @@ -1,15 +1,45 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import List, Optional from typing_extensions import Literal +from pydantic import Field as FieldInfo + from ....._models import BaseModel -from ..credential import Credential -__all__ = ["FieldUpdateResponse"] +__all__ = ["FieldUpdateResponse", "Data", "DataField"] + + +class DataField(BaseModel): + field_type: Literal[ + "email", "username", "password", "api_token", "phone_number", "two_factor_secret", "backup_codes" + ] = FieldInfo(alias="fieldType") + + value: str + + +class Data(BaseModel): + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + credential_name: str = FieldInfo(alias="credentialName") + + fields: List[DataField] + + owner_id: str = FieldInfo(alias="ownerId") + + package_name: str = FieldInfo(alias="packageName") + + secret_path: str = FieldInfo(alias="secretPath") + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use createdBy (same value — the creating actor). + + Null for credentials created before rollout. + """ class FieldUpdateResponse(BaseModel): - data: Credential + data: Data message: str diff --git a/src/mobilerun_sdk/types/device_create_params.py b/src/mobilerun_sdk/types/device_create_params.py index f674c92f..4596899e 100644 --- a/src/mobilerun_sdk/types/device_create_params.py +++ b/src/mobilerun_sdk/types/device_create_params.py @@ -3,16 +3,15 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from .._types import SequenceNotStr from .._utils import PropertyInfo -from .shared_params.socks5 import Socks5 from .shared_params.location import Location from .shared_params.device_carrier import DeviceCarrier from .shared_params.device_identifiers import DeviceIdentifiers -__all__ = ["DeviceCreateParams", "Proxy", "ProxyConnect"] +__all__ = ["DeviceCreateParams", "Proxy", "ProxyConnect", "ProxySocks5"] class DeviceCreateParams(TypedDict, total=False): @@ -84,6 +83,16 @@ class ProxyConnect(TypedDict, total=False): """ +class ProxySocks5(TypedDict, total=False): + host: Required[str] + + password: Required[str] + + port: Required[int] + + user: Required[str] + + class Proxy(TypedDict, total=False): connect: ProxyConnect @@ -91,4 +100,4 @@ class Proxy(TypedDict, total=False): smart_ip: Annotated[bool, PropertyInfo(alias="smartIp")] - socks5: Socks5 + socks5: ProxySocks5 diff --git a/src/mobilerun_sdk/types/device.py b/src/mobilerun_sdk/types/device_create_response.py similarity index 95% rename from src/mobilerun_sdk/types/device.py rename to src/mobilerun_sdk/types/device_create_response.py index a8b53e13..c792c9f7 100644 --- a/src/mobilerun_sdk/types/device.py +++ b/src/mobilerun_sdk/types/device_create_response.py @@ -7,10 +7,10 @@ from .._models import BaseModel -__all__ = ["Device"] +__all__ = ["DeviceCreateResponse"] -class Device(BaseModel): +class DeviceCreateResponse(BaseModel): id: str active_task_id: str = FieldInfo(alias="activeTaskId") diff --git a/src/mobilerun_sdk/types/device_list_response.py b/src/mobilerun_sdk/types/device_list_response.py index e748a8ee..f8c1a26a 100644 --- a/src/mobilerun_sdk/types/device_list_response.py +++ b/src/mobilerun_sdk/types/device_list_response.py @@ -1,18 +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 pydantic import Field as FieldInfo -from .device import Device from .._models import BaseModel from .shared.meta import Meta -__all__ = ["DeviceListResponse"] +__all__ = ["DeviceListResponse", "Item"] + + +class Item(BaseModel): + id: str + + active_task_id: str = FieldInfo(alias="activeTaskId") + + assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None) + + created_at: datetime = FieldInfo(alias="createdAt") + + name: str + + state: str + + state_message: str = FieldInfo(alias="stateMessage") + + stream_url: str = FieldInfo(alias="streamUrl") + + task_count: int = FieldInfo(alias="taskCount") + + terminates_at: Optional[datetime] = FieldInfo(alias="terminatesAt", default=None) + + type: str + + updated_at: datetime = FieldInfo(alias="updatedAt") + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + billing_strategy: Optional[str] = FieldInfo(alias="billingStrategy", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + provider_id: Optional[str] = FieldInfo(alias="providerId", default=None) + + stream_token: Optional[str] = FieldInfo(alias="streamToken", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId/createdBy.""" class DeviceListResponse(BaseModel): - items: Optional[List[Device]] = None + items: Optional[List[Item]] = None pagination: Meta diff --git a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py new file mode 100644 index 00000000..d8b598b2 --- /dev/null +++ b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py @@ -0,0 +1,62 @@ +# 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__ = ["DeviceRetrieveCapabilitiesResponse", "Capabilities"] + + +class Capabilities(BaseModel): + accessibility: bool + + agent: bool + + apps: bool + + browser: bool + + camera_injection: bool = FieldInfo(alias="cameraInjection") + + esim: bool + + files: bool + + fingerprint: bool + + frida: bool + + geo: bool + + human_touch: bool = FieldInfo(alias="humanTouch") + + language: bool + + logcat: bool + + microphone_injection: bool = FieldInfo(alias="microphoneInjection") + + proxy: bool + + reset: bool + + shell: bool + + spoofing: bool + + stop: bool + + stream: bool + + time: bool + + +class DeviceRetrieveCapabilitiesResponse(BaseModel): + capabilities: Capabilities + + device_type: str = FieldInfo(alias="deviceType") + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/device_retrieve_response.py b/src/mobilerun_sdk/types/device_retrieve_response.py new file mode 100644 index 00000000..6735522c --- /dev/null +++ b/src/mobilerun_sdk/types/device_retrieve_response.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DeviceRetrieveResponse"] + + +class DeviceRetrieveResponse(BaseModel): + id: str + + active_task_id: str = FieldInfo(alias="activeTaskId") + + assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None) + + created_at: datetime = FieldInfo(alias="createdAt") + + name: str + + state: str + + state_message: str = FieldInfo(alias="stateMessage") + + stream_url: str = FieldInfo(alias="streamUrl") + + task_count: int = FieldInfo(alias="taskCount") + + terminates_at: Optional[datetime] = FieldInfo(alias="terminatesAt", default=None) + + type: str + + updated_at: datetime = FieldInfo(alias="updatedAt") + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + billing_strategy: Optional[str] = FieldInfo(alias="billingStrategy", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + provider_id: Optional[str] = FieldInfo(alias="providerId", default=None) + + stream_token: Optional[str] = FieldInfo(alias="streamToken", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId/createdBy.""" diff --git a/src/mobilerun_sdk/types/device_set_name_response.py b/src/mobilerun_sdk/types/device_set_name_response.py new file mode 100644 index 00000000..f7976eea --- /dev/null +++ b/src/mobilerun_sdk/types/device_set_name_response.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DeviceSetNameResponse"] + + +class DeviceSetNameResponse(BaseModel): + id: str + + active_task_id: str = FieldInfo(alias="activeTaskId") + + assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None) + + created_at: datetime = FieldInfo(alias="createdAt") + + name: str + + state: str + + state_message: str = FieldInfo(alias="stateMessage") + + stream_url: str = FieldInfo(alias="streamUrl") + + task_count: int = FieldInfo(alias="taskCount") + + terminates_at: Optional[datetime] = FieldInfo(alias="terminatesAt", default=None) + + type: str + + updated_at: datetime = FieldInfo(alias="updatedAt") + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + billing_strategy: Optional[str] = FieldInfo(alias="billingStrategy", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + provider_id: Optional[str] = FieldInfo(alias="providerId", default=None) + + stream_token: Optional[str] = FieldInfo(alias="streamToken", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId/createdBy.""" diff --git a/src/mobilerun_sdk/types/device_wait_ready_response.py b/src/mobilerun_sdk/types/device_wait_ready_response.py new file mode 100644 index 00000000..73a50c61 --- /dev/null +++ b/src/mobilerun_sdk/types/device_wait_ready_response.py @@ -0,0 +1,52 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["DeviceWaitReadyResponse"] + + +class DeviceWaitReadyResponse(BaseModel): + id: str + + active_task_id: str = FieldInfo(alias="activeTaskId") + + assigned_at: Optional[datetime] = FieldInfo(alias="assignedAt", default=None) + + created_at: datetime = FieldInfo(alias="createdAt") + + name: str + + state: str + + state_message: str = FieldInfo(alias="stateMessage") + + stream_url: str = FieldInfo(alias="streamUrl") + + task_count: int = FieldInfo(alias="taskCount") + + terminates_at: Optional[datetime] = FieldInfo(alias="terminatesAt", default=None) + + type: str + + updated_at: datetime = FieldInfo(alias="updatedAt") + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + billing_strategy: Optional[str] = FieldInfo(alias="billingStrategy", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + provider_id: Optional[str] = FieldInfo(alias="providerId", default=None) + + stream_token: Optional[str] = FieldInfo(alias="streamToken", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId/createdBy.""" diff --git a/src/mobilerun_sdk/types/devices/__init__.py b/src/mobilerun_sdk/types/devices/__init__.py index dcd2cfaf..18dfbe66 100644 --- a/src/mobilerun_sdk/types/devices/__init__.py +++ b/src/mobilerun_sdk/types/devices/__init__.py @@ -2,8 +2,6 @@ from __future__ import annotations -from .rect import Rect as Rect -from .file_info import FileInfo as FileInfo from .a11_y_node import A11YNode as A11YNode from .app_list_params import AppListParams as AppListParams from .app_stop_params import AppStopParams as AppStopParams @@ -24,6 +22,7 @@ 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 .kiosk_enable_params import KioskEnableParams as KioskEnableParams from .language_set_params import LanguageSetParams as LanguageSetParams from .location_set_params import LocationSetParams as LocationSetParams from .package_list_params import PackageListParams as PackageListParams @@ -31,6 +30,7 @@ from .timezone_set_params import TimezoneSetParams as TimezoneSetParams from .action_global_params import ActionGlobalParams as ActionGlobalParams from .esim_activate_params import EsimActivateParams as EsimActivateParams +from .esim_status_response import EsimStatusResponse as EsimStatusResponse from .file_download_params import FileDownloadParams as FileDownloadParams from .proxy_connect_params import ProxyConnectParams as ProxyConnectParams from .keyboard_write_params import KeyboardWriteParams as KeyboardWriteParams @@ -38,10 +38,27 @@ from .package_list_response import PackageListResponse as PackageListResponse from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams from .proxy_status_response import ProxyStatusResponse as ProxyStatusResponse +from .recording_list_params import RecordingListParams as RecordingListParams from .timezone_get_response import TimezoneGetResponse as TimezoneGetResponse from .esim_activate_response import EsimActivateResponse as EsimActivateResponse from .file_download_response import FileDownloadResponse as FileDownloadResponse +from .recording_start_params import RecordingStartParams as RecordingStartParams +from .esim_set_roaming_params import EsimSetRoamingParams as EsimSetRoamingParams +from .recording_list_response import RecordingListResponse as RecordingListResponse +from .recording_stop_response import RecordingStopResponse as RecordingStopResponse from .state_screenshot_params import StateScreenshotParams as StateScreenshotParams +from .recording_start_response import RecordingStartResponse as RecordingStartResponse +from .recording_status_response import RecordingStatusResponse as RecordingStatusResponse from .state_screenshot_response import StateScreenshotResponse as StateScreenshotResponse +from .app_list_installs_response import AppListInstallsResponse as AppListInstallsResponse +from .media_session_create_params import MediaSessionCreateParams as MediaSessionCreateParams +from .browser_execute_script_params import BrowserExecuteScriptParams as BrowserExecuteScriptParams +from .media_session_create_response import MediaSessionCreateResponse as MediaSessionCreateResponse from .action_overlay_visible_response import ActionOverlayVisibleResponse as ActionOverlayVisibleResponse +from .browser_execute_script_response import BrowserExecuteScriptResponse as BrowserExecuteScriptResponse +from .media_session_activate_response import MediaSessionActivateResponse as MediaSessionActivateResponse from .action_set_overlay_visible_params import ActionSetOverlayVisibleParams as ActionSetOverlayVisibleParams +from .deep_link_execute_deep_link_params import DeepLinkExecuteDeepLinkParams as DeepLinkExecuteDeepLinkParams +from .media_session_retrieve_current_response import ( + MediaSessionRetrieveCurrentResponse as MediaSessionRetrieveCurrentResponse, +) diff --git a/src/mobilerun_sdk/types/devices/app_list_installs_response.py b/src/mobilerun_sdk/types/devices/app_list_installs_response.py new file mode 100644 index 00000000..796f7b2a --- /dev/null +++ b/src/mobilerun_sdk/types/devices/app_list_installs_response.py @@ -0,0 +1,42 @@ +# 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 + +__all__ = ["AppListInstallsResponse", "Install"] + + +class Install(BaseModel): + app_id: str = FieldInfo(alias="appId") + """Android package name or iOS bundle id""" + + platform: str + """android or ios""" + + started_at: datetime = FieldInfo(alias="startedAt") + + status: Literal["running", "succeeded", "failed"] + """ + On iOS MDM devices, succeeded means the install command was accepted by the + device's MDM channel, not that the install finished on-device. + """ + + updated_at: datetime = FieldInfo(alias="updatedAt") + + error_class: Optional[str] = FieldInfo(alias="errorClass", default=None) + """Closed set: download_failed, adb_install_failed, panic, timeout, failed. + + Only present when status is failed. + """ + + +class AppListInstallsResponse(BaseModel): + installs: Optional[List[Install]] = None + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/devices/browser_execute_script_params.py b/src/mobilerun_sdk/types/devices/browser_execute_script_params.py new file mode 100644 index 00000000..7b7e1ac5 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/browser_execute_script_params.py @@ -0,0 +1,21 @@ +# 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__ = ["BrowserExecuteScriptParams"] + + +class BrowserExecuteScriptParams(TypedDict, total=False): + script: Required[str] + """ + JavaScript expression to evaluate in the device's foreground Chrome tab (CDP + Runtime.evaluate). It is an expression, not a function body — the expression's + value is returned (no top-level 'return'). Must evaluate to a JSON-serializable + value; wrap multi-statement logic in an IIFE, e.g. (() => { ... ; return x })(). + """ + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/browser_execute_script_response.py b/src/mobilerun_sdk/types/devices/browser_execute_script_response.py new file mode 100644 index 00000000..5197f22b --- /dev/null +++ b/src/mobilerun_sdk/types/devices/browser_execute_script_response.py @@ -0,0 +1,21 @@ +# 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__ = ["BrowserExecuteScriptResponse"] + + +class BrowserExecuteScriptResponse(BaseModel): + result: object + """JSON-serialized return value of the script (null if it returned undefined). + + Non-JSON-serializable numbers (Infinity, NaN, -0) are returned as their string + representation. + """ + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/devices/deep_link_execute_deep_link_params.py b/src/mobilerun_sdk/types/devices/deep_link_execute_deep_link_params.py new file mode 100644 index 00000000..ce583e71 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/deep_link_execute_deep_link_params.py @@ -0,0 +1,31 @@ +# 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__ = ["DeepLinkExecuteDeepLinkParams"] + + +class DeepLinkExecuteDeepLinkParams(TypedDict, total=False): + deep_link: Required[Annotated[str, PropertyInfo(alias="deepLink")]] + """Deep link to open (e.g. myapp://path or https://example.com/path)""" + + action: str + """Android only: intent action to dispatch. + + Defaults to android.intent.action.VIEW. + """ + + bundle_id: Annotated[str, PropertyInfo(alias="bundleId")] + """Reserved for targeting a specific iOS app; currently rejected as unsupported.""" + + package_name: Annotated[str, PropertyInfo(alias="packageName")] + """Android only: package to receive the intent (e.g. + + com.example.app). Omit to let the system pick the handler. + """ + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/esim/__init__.py b/src/mobilerun_sdk/types/devices/esim/__init__.py new file mode 100644 index 00000000..35f8e7c1 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim/__init__.py @@ -0,0 +1,7 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .apn_set_params import ApnSetParams as ApnSetParams +from .apn_list_response import ApnListResponse as ApnListResponse +from .apn_select_params import ApnSelectParams as ApnSelectParams diff --git a/src/mobilerun_sdk/types/devices/esim/apn_list_response.py b/src/mobilerun_sdk/types/devices/esim/apn_list_response.py new file mode 100644 index 00000000..41bd1451 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim/apn_list_response.py @@ -0,0 +1,35 @@ +# 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__ = ["ApnListResponse", "ApnListResponseItem"] + + +class ApnListResponseItem(BaseModel): + id: int + + apn: str + + is_preferred: bool = FieldInfo(alias="isPreferred") + + mcc: str + + mnc: str + + name: str + + protocol: str + + roaming_protocol: str = FieldInfo(alias="roamingProtocol") + + sub_id: int = FieldInfo(alias="subId") + + type: str + + +ApnListResponse: TypeAlias = List[ApnListResponseItem] diff --git a/src/mobilerun_sdk/types/devices/esim/apn_select_params.py b/src/mobilerun_sdk/types/devices/esim/apn_select_params.py new file mode 100644 index 00000000..ca44100a --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim/apn_select_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__ = ["ApnSelectParams"] + + +class ApnSelectParams(TypedDict, total=False): + apn_id: Required[Annotated[int, PropertyInfo(alias="apnId")]] + + sub_id: Required[Annotated[int, PropertyInfo(alias="subId")]] + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/esim/apn_set_params.py b/src/mobilerun_sdk/types/devices/esim/apn_set_params.py new file mode 100644 index 00000000..a9b8d4be --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim/apn_set_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 Required, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ApnSetParams"] + + +class ApnSetParams(TypedDict, total=False): + apn: Required[str] + + mcc: Required[str] + + mnc: Required[str] + + name: Required[str] + + protocol: Required[str] + + roaming_protocol: Required[Annotated[str, PropertyInfo(alias="roamingProtocol")]] + + sub_id: Required[Annotated[int, PropertyInfo(alias="subId")]] + + type: Required[str] + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/esim_set_roaming_params.py b/src/mobilerun_sdk/types/devices/esim_set_roaming_params.py new file mode 100644 index 00000000..218544c0 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim_set_roaming_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__ = ["EsimSetRoamingParams"] + + +class EsimSetRoamingParams(TypedDict, total=False): + enabled: Required[bool] + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/esim_status_response.py b/src/mobilerun_sdk/types/devices/esim_status_response.py new file mode 100644 index 00000000..9a42b6eb --- /dev/null +++ b/src/mobilerun_sdk/types/devices/esim_status_response.py @@ -0,0 +1,35 @@ +# 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__ = ["EsimStatusResponse", "EsimStatusResponseItem"] + + +class EsimStatusResponseItem(BaseModel): + carrier: str + + data_roaming_enabled: bool = FieldInfo(alias="dataRoamingEnabled") + + data_state: str = FieldInfo(alias="dataState") + + is_roaming: bool = FieldInfo(alias="isRoaming") + + mobile_data_enabled: bool = FieldInfo(alias="mobileDataEnabled") + + network_type: str = FieldInfo(alias="networkType") + + operator: str + + phone_type: str = FieldInfo(alias="phoneType") + + sim_state: str = FieldInfo(alias="simState") + + sub_id: int = FieldInfo(alias="subId") + + +EsimStatusResponse: TypeAlias = List[EsimStatusResponseItem] diff --git a/src/mobilerun_sdk/types/devices/file_info.py b/src/mobilerun_sdk/types/devices/file_info.py deleted file mode 100644 index ed09c7be..00000000 --- a/src/mobilerun_sdk/types/devices/file_info.py +++ /dev/null @@ -1,51 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel -from ..shared.permission_set import PermissionSet - -__all__ = ["FileInfo", "Permissions", "PermissionsSpecial"] - - -class PermissionsSpecial(BaseModel): - set_gid: bool = FieldInfo(alias="setGid") - - set_uid: bool = FieldInfo(alias="setUid") - - sticky: bool - - -class Permissions(BaseModel): - group: PermissionSet - - others: PermissionSet - - owner: PermissionSet - - special: PermissionsSpecial - - -class FileInfo(BaseModel): - extended_attributes: bool = FieldInfo(alias="extendedAttributes") - - group: str - - hard_links: int = FieldInfo(alias="hardLinks") - - modified_at: datetime = FieldInfo(alias="modifiedAt") - - name: str - - owner: str - - permissions: Permissions - - size: int - - type: str - - symlink_target: Optional[str] = FieldInfo(alias="symlinkTarget", default=None) diff --git a/src/mobilerun_sdk/types/devices/file_list_response.py b/src/mobilerun_sdk/types/devices/file_list_response.py index 527b7fab..3a54fa88 100644 --- a/src/mobilerun_sdk/types/devices/file_list_response.py +++ b/src/mobilerun_sdk/types/devices/file_list_response.py @@ -1,17 +1,58 @@ # 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 -from .file_info import FileInfo +from ..shared.permission_set import PermissionSet -__all__ = ["FileListResponse"] +__all__ = ["FileListResponse", "File", "FilePermissions", "FilePermissionsSpecial"] + + +class FilePermissionsSpecial(BaseModel): + set_gid: bool = FieldInfo(alias="setGid") + + set_uid: bool = FieldInfo(alias="setUid") + + sticky: bool + + +class FilePermissions(BaseModel): + group: PermissionSet + + others: PermissionSet + + owner: PermissionSet + + special: FilePermissionsSpecial + + +class File(BaseModel): + extended_attributes: bool = FieldInfo(alias="extendedAttributes") + + group: str + + hard_links: int = FieldInfo(alias="hardLinks") + + modified_at: datetime = FieldInfo(alias="modifiedAt") + + name: str + + owner: str + + permissions: FilePermissions + + size: int + + type: str + + symlink_target: Optional[str] = FieldInfo(alias="symlinkTarget", default=None) class FileListResponse(BaseModel): - files: Optional[List[FileInfo]] = None + files: Optional[List[File]] = None path: str diff --git a/src/mobilerun_sdk/types/package_credentials_param.py b/src/mobilerun_sdk/types/devices/kiosk_enable_params.py similarity index 50% rename from src/mobilerun_sdk/types/package_credentials_param.py rename to src/mobilerun_sdk/types/devices/kiosk_enable_params.py index 87162c55..580b6807 100644 --- a/src/mobilerun_sdk/types/package_credentials_param.py +++ b/src/mobilerun_sdk/types/devices/kiosk_enable_params.py @@ -4,13 +4,13 @@ from typing_extensions import Required, Annotated, TypedDict -from .._types import SequenceNotStr -from .._utils import PropertyInfo +from ..._utils import PropertyInfo -__all__ = ["PackageCredentialsParam"] +__all__ = ["KioskEnableParams"] -class PackageCredentialsParam(TypedDict, total=False): - credential_names: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="credentialNames")]] - +class KioskEnableParams(TypedDict, total=False): package_name: Required[Annotated[str, PropertyInfo(alias="packageName")]] + """Package to lock the device to (Android lock-task mode).""" + + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/media_session_activate_response.py b/src/mobilerun_sdk/types/devices/media_session_activate_response.py new file mode 100644 index 00000000..1e474465 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/media_session_activate_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MediaSessionActivateResponse"] + + +class MediaSessionActivateResponse(BaseModel): + camera: bool + + expires_at: datetime = FieldInfo(alias="expiresAt") + + microphone: bool + + session_id: str = FieldInfo(alias="sessionId") + + state: Literal["created", "publishing", "active", "stopping", "closed", "failed"] + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/devices/media_session_create_params.py b/src/mobilerun_sdk/types/devices/media_session_create_params.py new file mode 100644 index 00000000..0d2a1390 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/media_session_create_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["MediaSessionCreateParams"] + + +class MediaSessionCreateParams(TypedDict, total=False): + camera: Required[bool] + """ + Publish combined browser audio and H264 video into the device's virtual + microphone and camera. Requires microphone=true. + """ + + microphone: Required[bool] + """Publish browser audio into the device's virtual microphone.""" diff --git a/src/mobilerun_sdk/types/devices/media_session_create_response.py b/src/mobilerun_sdk/types/devices/media_session_create_response.py new file mode 100644 index 00000000..2a78bba1 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/media_session_create_response.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MediaSessionCreateResponse"] + + +class MediaSessionCreateResponse(BaseModel): + camera: bool + + control_token: str = FieldInfo(alias="controlToken") + + expires_at: datetime = FieldInfo(alias="expiresAt") + + microphone: bool + + publish_token: str = FieldInfo(alias="publishToken") + + publish_url: str = FieldInfo(alias="publishUrl") + + session_id: str = FieldInfo(alias="sessionId") + + state: Literal["created", "publishing", "active", "stopping", "closed", "failed"] + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/devices/media_session_retrieve_current_response.py b/src/mobilerun_sdk/types/devices/media_session_retrieve_current_response.py new file mode 100644 index 00000000..5c0d2334 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/media_session_retrieve_current_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MediaSessionRetrieveCurrentResponse"] + + +class MediaSessionRetrieveCurrentResponse(BaseModel): + camera: bool + + expires_at: datetime = FieldInfo(alias="expiresAt") + + microphone: bool + + session_id: str = FieldInfo(alias="sessionId") + + state: Literal["created", "publishing", "active", "stopping", "closed", "failed"] + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" diff --git a/src/mobilerun_sdk/types/devices/recording_list_params.py b/src/mobilerun_sdk/types/devices/recording_list_params.py new file mode 100644 index 00000000..8cbbae26 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_list_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["RecordingListParams"] + + +class RecordingListParams(TypedDict, total=False): + status: str + + type: str diff --git a/src/mobilerun_sdk/types/devices/recording_list_response.py b/src/mobilerun_sdk/types/devices/recording_list_response.py new file mode 100644 index 00000000..32126898 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_list_response.py @@ -0,0 +1,68 @@ +# 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 TypeAlias + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = [ + "RecordingListResponse", + "RecordingListResponseItem", + "RecordingListResponseItemDisplay", + "RecordingListResponseItemVideo", +] + + +class RecordingListResponseItemDisplay(BaseModel): + height: int + + rotation: int + + width: int + + +class RecordingListResponseItemVideo(BaseModel): + duration_ms: int = FieldInfo(alias="durationMs") + + format: str + + size_bytes: int = FieldInfo(alias="sizeBytes") + + limited: Optional[bool] = None + + limit_reason: Optional[str] = FieldInfo(alias="limitReason", default=None) + + +class RecordingListResponseItem(BaseModel): + id: str + + actions: int + + device_id: str = FieldInfo(alias="deviceId") + + display: RecordingListResponseItemDisplay + + expires_at: datetime = FieldInfo(alias="expiresAt") + + name: str + + started_at: datetime = FieldInfo(alias="startedAt") + + status: str + + types: Optional[List[str]] = None + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None) + + error: Optional[str] = None + + video: Optional[RecordingListResponseItemVideo] = None + + +RecordingListResponse: TypeAlias = List[RecordingListResponseItem] diff --git a/src/mobilerun_sdk/types/devices/recording_start_params.py b/src/mobilerun_sdk/types/devices/recording_start_params.py new file mode 100644 index 00000000..621a86aa --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_start_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 import Optional +from typing_extensions import Annotated, TypedDict + +from ..._types import SequenceNotStr +from ..._utils import PropertyInfo + +__all__ = ["RecordingStartParams"] + + +class RecordingStartParams(TypedDict, total=False): + name: str + + retention_days: Annotated[int, PropertyInfo(alias="retentionDays")] + + types: Optional[SequenceNotStr[str]] diff --git a/src/mobilerun_sdk/types/devices/recording_start_response.py b/src/mobilerun_sdk/types/devices/recording_start_response.py new file mode 100644 index 00000000..c256aaec --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_start_response.py @@ -0,0 +1,59 @@ +# 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__ = ["RecordingStartResponse", "Display", "Video"] + + +class Display(BaseModel): + height: int + + rotation: int + + width: int + + +class Video(BaseModel): + duration_ms: int = FieldInfo(alias="durationMs") + + format: str + + size_bytes: int = FieldInfo(alias="sizeBytes") + + limited: Optional[bool] = None + + limit_reason: Optional[str] = FieldInfo(alias="limitReason", default=None) + + +class RecordingStartResponse(BaseModel): + id: str + + actions: int + + device_id: str = FieldInfo(alias="deviceId") + + display: Display + + expires_at: datetime = FieldInfo(alias="expiresAt") + + name: str + + started_at: datetime = FieldInfo(alias="startedAt") + + status: str + + types: Optional[List[str]] = None + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None) + + error: Optional[str] = None + + video: Optional[Video] = None diff --git a/src/mobilerun_sdk/types/devices/recording_status_response.py b/src/mobilerun_sdk/types/devices/recording_status_response.py new file mode 100644 index 00000000..3b52fbf7 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_status_response.py @@ -0,0 +1,59 @@ +# 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__ = ["RecordingStatusResponse", "Display", "Video"] + + +class Display(BaseModel): + height: int + + rotation: int + + width: int + + +class Video(BaseModel): + duration_ms: int = FieldInfo(alias="durationMs") + + format: str + + size_bytes: int = FieldInfo(alias="sizeBytes") + + limited: Optional[bool] = None + + limit_reason: Optional[str] = FieldInfo(alias="limitReason", default=None) + + +class RecordingStatusResponse(BaseModel): + id: str + + actions: int + + device_id: str = FieldInfo(alias="deviceId") + + display: Display + + expires_at: datetime = FieldInfo(alias="expiresAt") + + name: str + + started_at: datetime = FieldInfo(alias="startedAt") + + status: str + + types: Optional[List[str]] = None + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None) + + error: Optional[str] = None + + video: Optional[Video] = None diff --git a/src/mobilerun_sdk/types/devices/recording_stop_response.py b/src/mobilerun_sdk/types/devices/recording_stop_response.py new file mode 100644 index 00000000..98c4a0d2 --- /dev/null +++ b/src/mobilerun_sdk/types/devices/recording_stop_response.py @@ -0,0 +1,59 @@ +# 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__ = ["RecordingStopResponse", "Display", "Video"] + + +class Display(BaseModel): + height: int + + rotation: int + + width: int + + +class Video(BaseModel): + duration_ms: int = FieldInfo(alias="durationMs") + + format: str + + size_bytes: int = FieldInfo(alias="sizeBytes") + + limited: Optional[bool] = None + + limit_reason: Optional[str] = FieldInfo(alias="limitReason", default=None) + + +class RecordingStopResponse(BaseModel): + id: str + + actions: int + + device_id: str = FieldInfo(alias="deviceId") + + display: Display + + expires_at: datetime = FieldInfo(alias="expiresAt") + + name: str + + started_at: datetime = FieldInfo(alias="startedAt") + + status: str + + types: Optional[List[str]] = None + + schema_: Optional[str] = FieldInfo(alias="$schema", default=None) + """A URL to the JSON Schema for this object.""" + + ended_at: Optional[datetime] = FieldInfo(alias="endedAt", default=None) + + error: Optional[str] = None + + video: Optional[Video] = None diff --git a/src/mobilerun_sdk/types/devices/rect.py b/src/mobilerun_sdk/types/devices/rect.py deleted file mode 100644 index 1199a0e4..00000000 --- a/src/mobilerun_sdk/types/devices/rect.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["Rect"] - - -class Rect(BaseModel): - height: int - - width: int diff --git a/src/mobilerun_sdk/types/devices/state_ui_response.py b/src/mobilerun_sdk/types/devices/state_ui_response.py index 54fa0bcd..5c04c2a8 100644 --- a/src/mobilerun_sdk/types/devices/state_ui_response.py +++ b/src/mobilerun_sdk/types/devices/state_ui_response.py @@ -6,7 +6,6 @@ from pydantic import Field as FieldInfo -from .rect import Rect from ..._models import BaseModel __all__ = [ @@ -14,6 +13,7 @@ "DeviceContext", "DeviceContextDisplayMetrics", "DeviceContextFilteringParams", + "DeviceContextScreenBounds", "PhoneState", "PhoneStateFocusedElement", ] @@ -37,12 +37,18 @@ class DeviceContextFilteringParams(BaseModel): overlay_offset: int +class DeviceContextScreenBounds(BaseModel): + height: int + + width: int + + class DeviceContext(BaseModel): display_metrics: DeviceContextDisplayMetrics filtering_params: DeviceContextFilteringParams - screen_bounds: Rect + screen_bounds: DeviceContextScreenBounds class PhoneStateFocusedElement(BaseModel): diff --git a/src/mobilerun_sdk/types/devices/task_list_response.py b/src/mobilerun_sdk/types/devices/task_list_response.py index 2cc8956f..a7243edd 100644 --- a/src/mobilerun_sdk/types/devices/task_list_response.py +++ b/src/mobilerun_sdk/types/devices/task_list_response.py @@ -1,18 +1,26 @@ # 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 ..task import Task from ..._models import BaseModel from ..shared.meta import Meta -__all__ = ["TaskListResponse"] +__all__ = ["TaskListResponse", "Item"] + + +class Item(BaseModel): + created_at: datetime = FieldInfo(alias="createdAt") + + task_id: str = FieldInfo(alias="taskId") + + updated_at: datetime = FieldInfo(alias="updatedAt") class TaskListResponse(BaseModel): - items: Optional[List[Task]] = None + items: Optional[List[Item]] = None pagination: Meta diff --git a/src/mobilerun_sdk/types/esim_capacity_response.py b/src/mobilerun_sdk/types/esim_capacity_response.py new file mode 100644 index 00000000..69204004 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_capacity_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimCapacityResponse", "Data"] + + +class Data(BaseModel): + available: bool + + free_devices: int = FieldInfo(alias="freeDevices") + + +class EsimCapacityResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_confirm_payment_response.py b/src/mobilerun_sdk/types/esim_confirm_payment_response.py new file mode 100644 index 00000000..d981ab88 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_confirm_payment_response.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimConfirmPaymentResponse", "Data"] + + +class Data(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class EsimConfirmPaymentResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_create_params.py b/src/mobilerun_sdk/types/esim_create_params.py new file mode 100644 index 00000000..1e76c2c9 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_create_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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EsimCreateParams"] + + +class EsimCreateParams(TypedDict, total=False): + idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")] + """ + Client-supplied key; replaying the same key returns the original purchase + instead of buying again + """ diff --git a/src/mobilerun_sdk/types/esim_create_response.py b/src/mobilerun_sdk/types/esim_create_response.py new file mode 100644 index 00000000..11111f7a --- /dev/null +++ b/src/mobilerun_sdk/types/esim_create_response.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimCreateResponse", "Data"] + + +class Data(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class EsimCreateResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_import_params.py b/src/mobilerun_sdk/types/esim_import_params.py new file mode 100644 index 00000000..59433916 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_import_params.py @@ -0,0 +1,59 @@ +# 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 Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EsimImportParams"] + + +class EsimImportParams(TypedDict, total=False): + auto_install: Annotated[bool, PropertyInfo(alias="autoInstall")] + """Rent OFF only: dispatch install-on-device immediately after a successful import. + + No-op when ESIM_BYO_RENT_ENABLED=true. + """ + + carrier_name: Annotated[str, PropertyInfo(alias="carrierName")] + + confirmation_code: Annotated[str, PropertyInfo(alias="confirmationCode")] + + country_code: Annotated[str, PropertyInfo(alias="countryCode")] + + device_id: Annotated[str, PropertyInfo(alias="deviceId")] + """physedge device id to auto-install onto; requires autoInstall:true and rent OFF. + + Omit for a random pool device. + """ + + idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")] + """ + Client-supplied key; replaying the same key+request returns the original import + instead of importing again + """ + + lpa_code: Annotated[str, PropertyInfo(alias="lpaCode")] + """Full LPA activation code""" + + matching_id: Annotated[str, PropertyInfo(alias="matchingId")] + + msisdn: str + """ + Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never + used for routing + """ + + name: Optional[str] + """ + User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves + it unset. + """ + + notes: str + + smdp_address: Annotated[str, PropertyInfo(alias="smdpAddress")] + """SM-DP+ activation host — bare hostname ONLY, no port/scheme/path.""" diff --git a/src/mobilerun_sdk/types/esim_import_response.py b/src/mobilerun_sdk/types/esim_import_response.py new file mode 100644 index 00000000..5ab93dba --- /dev/null +++ b/src/mobilerun_sdk/types/esim_import_response.py @@ -0,0 +1,204 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = [ + "EsimImportResponse", + "Data", + "DataPublicEsim", + "DataEsimAwaitingPaymentResponse", + "DataEsimAwaitingPaymentResponseEsim", + "DataEsimImportInstallDispatchFailedResponse", + "DataEsimImportInstallDispatchFailedResponseInstallDispatch", +] + + +class DataPublicEsim(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class DataEsimAwaitingPaymentResponseEsim(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class DataEsimAwaitingPaymentResponse(BaseModel): + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + esim: DataEsimAwaitingPaymentResponseEsim + + rent_status: Literal["awaiting_payment"] = FieldInfo(alias="rentStatus") + + +class DataEsimImportInstallDispatchFailedResponseInstallDispatch(BaseModel): + ok: Literal[False] + + reason: str + + +class DataEsimImportInstallDispatchFailedResponse(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + install_dispatch: DataEsimImportInstallDispatchFailedResponseInstallDispatch = FieldInfo(alias="installDispatch") + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +Data: TypeAlias = Union[DataPublicEsim, DataEsimAwaitingPaymentResponse, DataEsimImportInstallDispatchFailedResponse] + + +class EsimImportResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_install_params.py b/src/mobilerun_sdk/types/esim_install_params.py new file mode 100644 index 00000000..ca23a433 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_install_params.py @@ -0,0 +1,14 @@ +# 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__ = ["EsimInstallParams"] + + +class EsimInstallParams(TypedDict, total=False): + device_id: Annotated[str, PropertyInfo(alias="deviceId")] + """physedge device id to install the eSIM onto; omit for a random pool device""" diff --git a/src/mobilerun_sdk/types/esim_install_response.py b/src/mobilerun_sdk/types/esim_install_response.py new file mode 100644 index 00000000..24ea2f92 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_install_response.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimInstallResponse", "Data"] + + +class Data(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class EsimInstallResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_install_status_response.py b/src/mobilerun_sdk/types/esim_install_status_response.py new file mode 100644 index 00000000..87f8c3e5 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_install_status_response.py @@ -0,0 +1,93 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimInstallStatusResponse", "Data", "DataEsim"] + + +class DataEsim(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class Data(BaseModel): + esim: DataEsim + + operation_id: Optional[str] = FieldInfo(alias="operationId", default=None) + + status: Optional[ + Literal[ + "installing", + "pending_download", + "downloading", + "downloaded", + "enabling", + "configuring_apn", + "active", + "download_failed", + "enable_failed", + "download_outcome_unknown", + "install_failed", + "physical_removal_unconfirmed", + "deleted", + ] + ] = None + + +class EsimInstallStatusResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_list_params.py b/src/mobilerun_sdk/types/esim_list_params.py new file mode 100644 index 00000000..a653308b --- /dev/null +++ b/src/mobilerun_sdk/types/esim_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_extensions import Literal, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["EsimListParams"] + + +class EsimListParams(TypedDict, total=False): + mine: Literal["true", "false"] + """Only include eSIMs created by the calling actor.""" + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] diff --git a/src/mobilerun_sdk/types/esim_list_response.py b/src/mobilerun_sdk/types/esim_list_response.py new file mode 100644 index 00000000..a0440fe0 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_list_response.py @@ -0,0 +1,76 @@ +# 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 .shared.pagination import Pagination + +__all__ = ["EsimListResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class Data(BaseModel): + items: List[DataItem] + + pagination: Pagination + + +class EsimListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_retrieve_response.py b/src/mobilerun_sdk/types/esim_retrieve_response.py new file mode 100644 index 00000000..41cf5a88 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_retrieve_response.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class EsimRetrieveResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_selector_response.py b/src/mobilerun_sdk/types/esim_selector_response.py new file mode 100644 index 00000000..7eedbf93 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_selector_response.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimSelectorResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + +class Data(BaseModel): + items: List[DataItem] + + +class EsimSelectorResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esim_update_params.py b/src/mobilerun_sdk/types/esim_update_params.py new file mode 100644 index 00000000..a0fdc6de --- /dev/null +++ b/src/mobilerun_sdk/types/esim_update_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 import Optional +from typing_extensions import TypedDict + +__all__ = ["EsimUpdateParams"] + + +class EsimUpdateParams(TypedDict, total=False): + msisdn: Optional[str] + """Self-reported E.164 MSISDN for this eSIM's line. + + Omit to leave unchanged; null/empty clears it. An unverified label — never used + for routing. + """ + + name: Optional[str] + """ + User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code + units; an emoji/flag may span several). Omit to leave unchanged; + null/empty/whitespace-only clears it. + """ diff --git a/src/mobilerun_sdk/types/esim_update_response.py b/src/mobilerun_sdk/types/esim_update_response.py new file mode 100644 index 00000000..407eb7d9 --- /dev/null +++ b/src/mobilerun_sdk/types/esim_update_response.py @@ -0,0 +1,69 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["EsimUpdateResponse", "Data"] + + +class Data(BaseModel): + id: str + + carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) + + iccid: Optional[str] = None + + msisdn: Optional[str] = None + + name: Optional[str] = None + + network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) + + source: Literal["stocked", "byo"] + + status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] + + subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + exempt: Optional[bool] = None + + rent_status: Optional[ + Literal[ + "not_applicable", + "exempt", + "inactive", + "awaiting_payment", + "active", + "cancel_pending", + "refund_pending", + "retiring", + "billing_error", + ] + ] = FieldInfo(alias="rentStatus", default=None) + + +class EsimUpdateResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esims/__init__.py b/src/mobilerun_sdk/types/esims/__init__.py new file mode 100644 index 00000000..d059c99c --- /dev/null +++ b/src/mobilerun_sdk/types/esims/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .message_list_params import MessageListParams as MessageListParams +from .message_send_params import MessageSendParams as MessageSendParams +from .message_list_response import MessageListResponse as MessageListResponse +from .message_send_response import MessageSendResponse as MessageSendResponse diff --git a/src/mobilerun_sdk/types/esims/message_list_params.py b/src/mobilerun_sdk/types/esims/message_list_params.py new file mode 100644 index 00000000..c55e68af --- /dev/null +++ b/src/mobilerun_sdk/types/esims/message_list_params.py @@ -0,0 +1,27 @@ +# 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__ = ["MessageListParams"] + + +class MessageListParams(TypedDict, total=False): + direction: Literal["all", "inbound", "outbound"] + + number_id: Annotated[str, PropertyInfo(alias="numberId")] + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + peer_key: Annotated[str, PropertyInfo(alias="peerKey")] + + peer_number: Annotated[str, PropertyInfo(alias="peerNumber")] + + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] diff --git a/src/mobilerun_sdk/types/esims/message_list_response.py b/src/mobilerun_sdk/types/esims/message_list_response.py new file mode 100644 index 00000000..077b2c78 --- /dev/null +++ b/src/mobilerun_sdk/types/esims/message_list_response.py @@ -0,0 +1,48 @@ +# 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 ..shared.pagination import Pagination + +__all__ = ["MessageListResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + id: str + + body: Optional[str] = None + + created_at: datetime = FieldInfo(alias="createdAt") + + delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) + + detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) + + direction: Literal["inbound", "outbound"] + + esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) + + occurred_at: datetime = FieldInfo(alias="occurredAt") + + peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) + + peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) + + provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None) + + status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] + + +class Data(BaseModel): + items: List[DataItem] + + pagination: Pagination + + +class MessageListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/esims/message_send_params.py b/src/mobilerun_sdk/types/esims/message_send_params.py new file mode 100644 index 00000000..48c2c65a --- /dev/null +++ b/src/mobilerun_sdk/types/esims/message_send_params.py @@ -0,0 +1,38 @@ +# 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__ = ["MessageSendParams"] + + +class MessageSendParams(TypedDict, total=False): + body: Required[str] + """ + SMS body text (max 320 chars — smaller than the admin tier's cap; see the + schema's own doc comment for why) + """ + + to: Required[str] + """ + Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); + rejected with 400 if it doesn't validate as E.164 afterward. + """ + + client_request_id: Annotated[str, PropertyInfo(alias="clientRequestId")] + """Client-supplied idempotency key, scoped to (owner, esimId, key). + + Replaying the same key + identical payload returns the original send; the same + key with a DIFFERENT payload is a 409 conflict. + """ + + delivery_report: Annotated[bool, PropertyInfo(alias="deliveryReport")] + """ + Wait for physedge to confirm carrier delivery before completing the send (adds + executor-side latency, never on this request — sends are always async/202). + Defaults to false for the public tier (opt-in, unlike the admin tier's + default-true). + """ diff --git a/src/mobilerun_sdk/types/esims/message_send_response.py b/src/mobilerun_sdk/types/esims/message_send_response.py new file mode 100644 index 00000000..86e545d6 --- /dev/null +++ b/src/mobilerun_sdk/types/esims/message_send_response.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MessageSendResponse", "Data"] + + +class Data(BaseModel): + id: str + + body: Optional[str] = None + + created_at: datetime = FieldInfo(alias="createdAt") + + delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) + + detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) + + direction: Literal["inbound", "outbound"] + + esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) + + occurred_at: datetime = FieldInfo(alias="occurredAt") + + peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) + + peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) + + provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None) + + status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] + + +class MessageSendResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/flow.py b/src/mobilerun_sdk/types/flow.py deleted file mode 100644 index 24984f3c..00000000 --- a/src/mobilerun_sdk/types/flow.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["Flow"] - - -class Flow(BaseModel): - id: str - - blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) - - consecutive_failures: int = FieldInfo(alias="consecutiveFailures") - - cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") - - cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) - - created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - description: Optional[str] = None - - device_ids: List[str] = FieldInfo(alias="deviceIds") - - enabled: bool - - health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") - - last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) - - last_failure_code: Optional[ - Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] - ] = FieldInfo(alias="lastFailureCode", default=None) - - last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) - - name: str - - notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") - - notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") - - notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) - - owner_id: str = FieldInfo(alias="ownerId") - - self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") - - self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") - - status: Literal["healthy", "failing", "blocked"] - - template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") - """Template-resolver semantics this flow runs under (MVA-23). - - 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed - (missing/forbidden throw, a whole-token null stays JSON null). Existing flows - stay 1; new flows default to 2. - """ - - trigger_id: str = FieldInfo(alias="triggerId") - - updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) - - user_id: str = FieldInfo(alias="userId") - """Deprecated: use ownerId (tenancy) / createdBy (actor).""" diff --git a/src/mobilerun_sdk/types/message_list_params.py b/src/mobilerun_sdk/types/message_list_params.py new file mode 100644 index 00000000..98ed9356 --- /dev/null +++ b/src/mobilerun_sdk/types/message_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__ = ["MessageListParams"] + + +class MessageListParams(TypedDict, total=False): + direction: Literal["all", "inbound", "outbound"] + + esim_id: Annotated[str, PropertyInfo(alias="esimId")] + + number_id: Annotated[str, PropertyInfo(alias="numberId")] + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + peer_key: Annotated[str, PropertyInfo(alias="peerKey")] + + peer_number: Annotated[str, PropertyInfo(alias="peerNumber")] + + status: Literal[ + "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" + ] diff --git a/src/mobilerun_sdk/types/message_list_response.py b/src/mobilerun_sdk/types/message_list_response.py new file mode 100644 index 00000000..aaaa20b6 --- /dev/null +++ b/src/mobilerun_sdk/types/message_list_response.py @@ -0,0 +1,48 @@ +# 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 .shared.pagination import Pagination + +__all__ = ["MessageListResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + id: str + + body: Optional[str] = None + + created_at: datetime = FieldInfo(alias="createdAt") + + delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) + + detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) + + direction: Literal["inbound", "outbound"] + + esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) + + occurred_at: datetime = FieldInfo(alias="occurredAt") + + peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) + + peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) + + provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None) + + status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] + + +class Data(BaseModel): + items: List[DataItem] + + pagination: Pagination + + +class MessageListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/messages/__init__.py b/src/mobilerun_sdk/types/messages/__init__.py new file mode 100644 index 00000000..d363e32d --- /dev/null +++ b/src/mobilerun_sdk/types/messages/__init__.py @@ -0,0 +1,8 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .conversation_list_params import ConversationListParams as ConversationListParams +from .conversation_list_response import ConversationListResponse as ConversationListResponse +from .conversation_mark_read_params import ConversationMarkReadParams as ConversationMarkReadParams +from .conversation_mark_read_response import ConversationMarkReadResponse as ConversationMarkReadResponse diff --git a/src/mobilerun_sdk/types/messages/conversation_list_params.py b/src/mobilerun_sdk/types/messages/conversation_list_params.py new file mode 100644 index 00000000..cc6c06b6 --- /dev/null +++ b/src/mobilerun_sdk/types/messages/conversation_list_params.py @@ -0,0 +1,25 @@ +# 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__ = ["ConversationListParams"] + + +class ConversationListParams(TypedDict, total=False): + cursor_last_message_id: Annotated[str, PropertyInfo(alias="cursorLastMessageId")] + + cursor_last_occurred_at: Annotated[ + Union[str, datetime], PropertyInfo(alias="cursorLastOccurredAt", format="iso8601") + ] + + esim_id: Annotated[str, PropertyInfo(alias="esimId")] + + limit: int + + number_id: Annotated[str, PropertyInfo(alias="numberId")] diff --git a/src/mobilerun_sdk/types/messages/conversation_list_response.py b/src/mobilerun_sdk/types/messages/conversation_list_response.py new file mode 100644 index 00000000..da1e4585 --- /dev/null +++ b/src/mobilerun_sdk/types/messages/conversation_list_response.py @@ -0,0 +1,49 @@ +# 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 + +__all__ = ["ConversationListResponse", "Data", "DataItem", "DataItemLastMessage", "DataNextCursor"] + + +class DataItemLastMessage(BaseModel): + id: str + + body: Optional[str] = None + + direction: Literal["inbound", "outbound"] + + occurred_at: datetime = FieldInfo(alias="occurredAt") + + status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] + + +class DataItem(BaseModel): + esim_ids: List[str] = FieldInfo(alias="esimIds") + + last_message: DataItemLastMessage = FieldInfo(alias="lastMessage") + + peer_key: str = FieldInfo(alias="peerKey") + + unread_count: int = FieldInfo(alias="unreadCount") + + +class DataNextCursor(BaseModel): + last_message_id: str = FieldInfo(alias="lastMessageId") + + last_occurred_at: datetime = FieldInfo(alias="lastOccurredAt") + + +class Data(BaseModel): + items: List[DataItem] + + next_cursor: Optional[DataNextCursor] = FieldInfo(alias="nextCursor", default=None) + + +class ConversationListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/messages/conversation_mark_read_params.py b/src/mobilerun_sdk/types/messages/conversation_mark_read_params.py new file mode 100644 index 00000000..264eb6c1 --- /dev/null +++ b/src/mobilerun_sdk/types/messages/conversation_mark_read_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 import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["ConversationMarkReadParams"] + + +class ConversationMarkReadParams(TypedDict, total=False): + peer_key: Required[Annotated[str, PropertyInfo(alias="peerKey")]] + """The thread's canonical peer key (see GET .../conversations)""" + + up_to_message_id: Required[Annotated[str, PropertyInfo(alias="upToMessageId")]] + + up_to_occurred_at: Required[Annotated[Union[str, datetime], PropertyInfo(alias="upToOccurredAt", format="iso8601")]] + """ + Mark inbound messages read up to (and including) this occurredAt/upToMessageId + cursor + """ diff --git a/src/mobilerun_sdk/types/messages/conversation_mark_read_response.py b/src/mobilerun_sdk/types/messages/conversation_mark_read_response.py new file mode 100644 index 00000000..8d5262cb --- /dev/null +++ b/src/mobilerun_sdk/types/messages/conversation_mark_read_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ConversationMarkReadResponse", "Data"] + + +class Data(BaseModel): + updated: int + + +class ConversationMarkReadResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/notification_catalog_response.py b/src/mobilerun_sdk/types/notification_catalog_response.py new file mode 100644 index 00000000..266a0184 --- /dev/null +++ b/src/mobilerun_sdk/types/notification_catalog_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["NotificationCatalogResponse", "Data", "DataEvent"] + + +class DataEvent(BaseModel): + description: str + + label: str + + type: str + + toast: Optional[bool] = None + + +class Data(BaseModel): + events: List[DataEvent] + + label: str + + source: str + + +class NotificationCatalogResponse(BaseModel): + data: List[Data] diff --git a/src/mobilerun_sdk/types/notification_get_preferences_response.py b/src/mobilerun_sdk/types/notification_get_preferences_response.py new file mode 100644 index 00000000..f32ecbd3 --- /dev/null +++ b/src/mobilerun_sdk/types/notification_get_preferences_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["NotificationGetPreferencesResponse", "Data"] + + +class Data(BaseModel): + muted_types: List[str] = FieldInfo(alias="mutedTypes") + + +class NotificationGetPreferencesResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/notification_update_preferences_params.py b/src/mobilerun_sdk/types/notification_update_preferences_params.py new file mode 100644 index 00000000..13ef579a --- /dev/null +++ b/src/mobilerun_sdk/types/notification_update_preferences_params.py @@ -0,0 +1,14 @@ +# 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 .._types import SequenceNotStr +from .._utils import PropertyInfo + +__all__ = ["NotificationUpdatePreferencesParams"] + + +class NotificationUpdatePreferencesParams(TypedDict, total=False): + muted_types: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="mutedTypes")]] diff --git a/src/mobilerun_sdk/types/notification_update_preferences_response.py b/src/mobilerun_sdk/types/notification_update_preferences_response.py new file mode 100644 index 00000000..f95f1629 --- /dev/null +++ b/src/mobilerun_sdk/types/notification_update_preferences_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["NotificationUpdatePreferencesResponse", "Data"] + + +class Data(BaseModel): + muted_types: List[str] = FieldInfo(alias="mutedTypes") + + +class NotificationUpdatePreferencesResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_countries_response.py b/src/mobilerun_sdk/types/number_countries_response.py new file mode 100644 index 00000000..893e05a7 --- /dev/null +++ b/src/mobilerun_sdk/types/number_countries_response.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["NumberCountriesResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + country: str + + in_stock: bool = FieldInfo(alias="inStock") + + name: str + + plan_id: str = FieldInfo(alias="planId") + + +class Data(BaseModel): + items: List[DataItem] + + +class NumberCountriesResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_create_params.py b/src/mobilerun_sdk/types/number_create_params.py new file mode 100644 index 00000000..5083087f --- /dev/null +++ b/src/mobilerun_sdk/types/number_create_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__ = ["NumberCreateParams"] + + +class NumberCreateParams(TypedDict, total=False): + billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")] + """ + Prefer a free package seat ('included', default) or force the paid checkout + ('rent') + """ + + country: str + """Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. + + Cannot be combined with `purpose`. + """ + + purpose: str + """Optional Mobilerun Phone purpose slug from GET /numbers/purposes.""" + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + """Optional request idempotency key.""" diff --git a/src/mobilerun_sdk/types/number_create_response.py b/src/mobilerun_sdk/types/number_create_response.py new file mode 100644 index 00000000..b5b42413 --- /dev/null +++ b/src/mobilerun_sdk/types/number_create_response.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["NumberCreateResponse", "Data"] + + +class Data(BaseModel): + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + number_id: str = FieldInfo(alias="numberId") + + state: Literal["awaiting_payment", "provisioning"] + + +class NumberCreateResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_delete_response.py b/src/mobilerun_sdk/types/number_delete_response.py new file mode 100644 index 00000000..4049d3d8 --- /dev/null +++ b/src/mobilerun_sdk/types/number_delete_response.py @@ -0,0 +1,43 @@ +# 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 + +__all__ = ["NumberDeleteResponse", "Data"] + + +class Data(BaseModel): + id: str + + cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") + + cancellable: bool + + can_send: bool = FieldInfo(alias="canSend") + + capabilities: Optional[List[Literal["sms", "voice"]]] = None + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None) + + purpose: Optional[str] = None + + state: Literal["awaiting_payment", "provisioning", "active", "cancel_scheduled", "expired", "failed"] + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + +class NumberDeleteResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_list_params.py b/src/mobilerun_sdk/types/number_list_params.py new file mode 100644 index 00000000..111cd645 --- /dev/null +++ b/src/mobilerun_sdk/types/number_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__ = ["NumberListParams"] + + +class NumberListParams(TypedDict, total=False): + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] diff --git a/src/mobilerun_sdk/types/number_list_response.py b/src/mobilerun_sdk/types/number_list_response.py new file mode 100644 index 00000000..2ada07db --- /dev/null +++ b/src/mobilerun_sdk/types/number_list_response.py @@ -0,0 +1,50 @@ +# 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 .shared.pagination import Pagination + +__all__ = ["NumberListResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + id: str + + cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") + + cancellable: bool + + can_send: bool = FieldInfo(alias="canSend") + + capabilities: Optional[List[Literal["sms", "voice"]]] = None + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None) + + purpose: Optional[str] = None + + state: Literal["awaiting_payment", "provisioning", "active", "cancel_scheduled", "expired", "failed"] + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + +class Data(BaseModel): + items: List[DataItem] + + pagination: Pagination + + +class NumberListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_purposes_response.py b/src/mobilerun_sdk/types/number_purposes_response.py new file mode 100644 index 00000000..a2e7b87c --- /dev/null +++ b/src/mobilerun_sdk/types/number_purposes_response.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel + +__all__ = ["NumberPurposesResponse", "Data", "DataItem"] + + +class DataItem(BaseModel): + label: str + + slug: str + + +class Data(BaseModel): + items: List[DataItem] + + +class NumberPurposesResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/number_retrieve_response.py b/src/mobilerun_sdk/types/number_retrieve_response.py new file mode 100644 index 00000000..70a88c99 --- /dev/null +++ b/src/mobilerun_sdk/types/number_retrieve_response.py @@ -0,0 +1,43 @@ +# 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 + +__all__ = ["NumberRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") + + cancellable: bool + + can_send: bool = FieldInfo(alias="canSend") + + capabilities: Optional[List[Literal["sms", "voice"]]] = None + + checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) + + country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + + phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None) + + purpose: Optional[str] = None + + state: Literal["awaiting_payment", "provisioning", "active", "cancel_scheduled", "expired", "failed"] + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + +class NumberRetrieveResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/numbers/__init__.py b/src/mobilerun_sdk/types/numbers/__init__.py new file mode 100644 index 00000000..867594a6 --- /dev/null +++ b/src/mobilerun_sdk/types/numbers/__init__.py @@ -0,0 +1,6 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .message_list_params import MessageListParams as MessageListParams +from .message_list_response import MessageListResponse as MessageListResponse diff --git a/src/mobilerun_sdk/types/numbers/message_list_params.py b/src/mobilerun_sdk/types/numbers/message_list_params.py new file mode 100644 index 00000000..3137b0cf --- /dev/null +++ b/src/mobilerun_sdk/types/numbers/message_list_params.py @@ -0,0 +1,21 @@ +# 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 Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["MessageListParams"] + + +class MessageListParams(TypedDict, total=False): + direction: Literal["all", "inbound", "outbound"] + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + since: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/mobilerun_sdk/types/numbers/message_list_response.py b/src/mobilerun_sdk/types/numbers/message_list_response.py new file mode 100644 index 00000000..3d9b3c3d --- /dev/null +++ b/src/mobilerun_sdk/types/numbers/message_list_response.py @@ -0,0 +1,59 @@ +# 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 + +__all__ = ["MessageListResponse", "Data", "DataItem", "DataPagination"] + + +class DataItem(BaseModel): + id: str + + body: Optional[str] = None + + created_at: datetime = FieldInfo(alias="createdAt") + + delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) + + detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) + + direction: Literal["inbound", "outbound"] + + esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) + + occurred_at: datetime = FieldInfo(alias="occurredAt") + + peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) + + peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) + + status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] + + +class DataPagination(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 Data(BaseModel): + items: List[DataItem] + + pagination: DataPagination + + +class MessageListResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/proxy_config.py b/src/mobilerun_sdk/types/proxy_config.py deleted file mode 100644 index 52d651cd..00000000 --- a/src/mobilerun_sdk/types/proxy_config.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Literal, Annotated, TypeAlias - -from pydantic import Field as FieldInfo - -from .._utils import PropertyInfo -from .._models import BaseModel - -__all__ = ["ProxyConfig", "Socks5ProxyConfig", "WireguardProxyConfig"] - - -class Socks5ProxyConfig(BaseModel): - host: str - - name: str - - password: str - - port: int - - protocol: Literal["socks5"] - - proxy_id: str = FieldInfo(alias="proxyId") - - user: str - - -class WireguardProxyConfig(BaseModel): - config: str - - name: str - - protocol: Literal["wireguard"] - - proxy_id: str = FieldInfo(alias="proxyId") - - -ProxyConfig: TypeAlias = Annotated[ - Union[Socks5ProxyConfig, WireguardProxyConfig], PropertyInfo(discriminator="protocol") -] diff --git a/src/mobilerun_sdk/types/proxy_create_response.py b/src/mobilerun_sdk/types/proxy_create_response.py index 72a8d2ca..f190a909 100644 --- a/src/mobilerun_sdk/types/proxy_create_response.py +++ b/src/mobilerun_sdk/types/proxy_create_response.py @@ -1,15 +1,32 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo from .._models import BaseModel -from .proxy_config import ProxyConfig +from .shared.socks5_proxy_config import Socks5ProxyConfig + +__all__ = ["ProxyCreateResponse", "Data", "DataWireguardProxyConfig"] + + +class DataWireguardProxyConfig(BaseModel): + config: str + + name: str + + protocol: Literal["wireguard"] + + proxy_id: str = FieldInfo(alias="proxyId") + -__all__ = ["ProxyCreateResponse"] +Data: TypeAlias = Annotated[Union[Socks5ProxyConfig, DataWireguardProxyConfig], PropertyInfo(discriminator="protocol")] class ProxyCreateResponse(BaseModel): - data: ProxyConfig + data: Data message: str diff --git a/src/mobilerun_sdk/types/proxy_delete_response.py b/src/mobilerun_sdk/types/proxy_delete_response.py index 872567b5..de40f406 100644 --- a/src/mobilerun_sdk/types/proxy_delete_response.py +++ b/src/mobilerun_sdk/types/proxy_delete_response.py @@ -1,15 +1,32 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo from .._models import BaseModel -from .proxy_config import ProxyConfig +from .shared.socks5_proxy_config import Socks5ProxyConfig + +__all__ = ["ProxyDeleteResponse", "Data", "DataWireguardProxyConfig"] + + +class DataWireguardProxyConfig(BaseModel): + config: str + + name: str + + protocol: Literal["wireguard"] + + proxy_id: str = FieldInfo(alias="proxyId") + -__all__ = ["ProxyDeleteResponse"] +Data: TypeAlias = Annotated[Union[Socks5ProxyConfig, DataWireguardProxyConfig], PropertyInfo(discriminator="protocol")] class ProxyDeleteResponse(BaseModel): - data: ProxyConfig + data: Data message: str diff --git a/src/mobilerun_sdk/types/proxy_list_response.py b/src/mobilerun_sdk/types/proxy_list_response.py index ff49af06..cc36799d 100644 --- a/src/mobilerun_sdk/types/proxy_list_response.py +++ b/src/mobilerun_sdk/types/proxy_list_response.py @@ -1,12 +1,29 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Union +from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo from .._models import BaseModel -from .proxy_config import ProxyConfig +from .shared.socks5_proxy_config import Socks5ProxyConfig + +__all__ = ["ProxyListResponse", "Data", "DataWireguardProxyConfig"] + + +class DataWireguardProxyConfig(BaseModel): + config: str + + name: str + + protocol: Literal["wireguard"] + + proxy_id: str = FieldInfo(alias="proxyId") + -__all__ = ["ProxyListResponse"] +Data: TypeAlias = Annotated[Union[Socks5ProxyConfig, DataWireguardProxyConfig], PropertyInfo(discriminator="protocol")] class ProxyListResponse(BaseModel): - data: List[ProxyConfig] + data: List[Data] diff --git a/src/mobilerun_sdk/types/proxy_retrieve_response.py b/src/mobilerun_sdk/types/proxy_retrieve_response.py index 6c6a1c53..dc48ce76 100644 --- a/src/mobilerun_sdk/types/proxy_retrieve_response.py +++ b/src/mobilerun_sdk/types/proxy_retrieve_response.py @@ -1,10 +1,29 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo from .._models import BaseModel -from .proxy_config import ProxyConfig +from .shared.socks5_proxy_config import Socks5ProxyConfig + +__all__ = ["ProxyRetrieveResponse", "Data", "DataWireguardProxyConfig"] + + +class DataWireguardProxyConfig(BaseModel): + config: str + + name: str + + protocol: Literal["wireguard"] + + proxy_id: str = FieldInfo(alias="proxyId") + -__all__ = ["ProxyRetrieveResponse"] +Data: TypeAlias = Annotated[Union[Socks5ProxyConfig, DataWireguardProxyConfig], PropertyInfo(discriminator="protocol")] class ProxyRetrieveResponse(BaseModel): - data: ProxyConfig + data: Data diff --git a/src/mobilerun_sdk/types/proxy_update_response.py b/src/mobilerun_sdk/types/proxy_update_response.py index f1578b4c..8e663e16 100644 --- a/src/mobilerun_sdk/types/proxy_update_response.py +++ b/src/mobilerun_sdk/types/proxy_update_response.py @@ -1,15 +1,32 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing_extensions import Literal +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias +from pydantic import Field as FieldInfo + +from .._utils import PropertyInfo from .._models import BaseModel -from .proxy_config import ProxyConfig +from .shared.socks5_proxy_config import Socks5ProxyConfig + +__all__ = ["ProxyUpdateResponse", "Data", "DataWireguardProxyConfig"] + + +class DataWireguardProxyConfig(BaseModel): + config: str + + name: str + + protocol: Literal["wireguard"] + + proxy_id: str = FieldInfo(alias="proxyId") + -__all__ = ["ProxyUpdateResponse"] +Data: TypeAlias = Annotated[Union[Socks5ProxyConfig, DataWireguardProxyConfig], PropertyInfo(discriminator="protocol")] class ProxyUpdateResponse(BaseModel): - data: ProxyConfig + data: Data message: str diff --git a/src/mobilerun_sdk/types/shared/__init__.py b/src/mobilerun_sdk/types/shared/__init__.py index 7d0f1161..76cc65fa 100644 --- a/src/mobilerun_sdk/types/shared/__init__.py +++ b/src/mobilerun_sdk/types/shared/__init__.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from .meta import Meta as Meta -from .socks5 import Socks5 as Socks5 from .location import Location as Location from .pagination import Pagination as Pagination from .device_spec import DeviceSpec as DeviceSpec @@ -9,3 +8,4 @@ from .permission_set import PermissionSet as PermissionSet from .pagination_meta import PaginationMeta as PaginationMeta from .device_identifiers import DeviceIdentifiers as DeviceIdentifiers +from .socks5_proxy_config import Socks5ProxyConfig as Socks5ProxyConfig diff --git a/src/mobilerun_sdk/types/shared/device_spec.py b/src/mobilerun_sdk/types/shared/device_spec.py index 582c47b6..92bd67e3 100644 --- a/src/mobilerun_sdk/types/shared/device_spec.py +++ b/src/mobilerun_sdk/types/shared/device_spec.py @@ -4,13 +4,12 @@ from pydantic import Field as FieldInfo -from .socks5 import Socks5 from .location import Location from ..._models import BaseModel from .device_carrier import DeviceCarrier from .device_identifiers import DeviceIdentifiers -__all__ = ["DeviceSpec", "Proxy", "ProxyConnect"] +__all__ = ["DeviceSpec", "Proxy", "ProxyConnect", "ProxySocks5"] class ProxyConnect(BaseModel): @@ -24,6 +23,16 @@ class ProxyConnect(BaseModel): """ +class ProxySocks5(BaseModel): + host: str + + password: str + + port: int + + user: str + + class Proxy(BaseModel): connect: Optional[ProxyConnect] = None @@ -31,7 +40,7 @@ class Proxy(BaseModel): smart_ip: Optional[bool] = FieldInfo(alias="smartIp", default=None) - socks5: Optional[Socks5] = None + socks5: Optional[ProxySocks5] = None class DeviceSpec(BaseModel): diff --git a/src/mobilerun_sdk/types/shared/socks5.py b/src/mobilerun_sdk/types/shared/socks5.py deleted file mode 100644 index 36791bd7..00000000 --- a/src/mobilerun_sdk/types/shared/socks5.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["Socks5"] - - -class Socks5(BaseModel): - host: str - - password: str - - port: int - - user: str diff --git a/src/mobilerun_sdk/types/shared/socks5_proxy_config.py b/src/mobilerun_sdk/types/shared/socks5_proxy_config.py new file mode 100644 index 00000000..538220c7 --- /dev/null +++ b/src/mobilerun_sdk/types/shared/socks5_proxy_config.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["Socks5ProxyConfig"] + + +class Socks5ProxyConfig(BaseModel): + host: str + + name: str + + password: str + + port: int + + protocol: Literal["socks5"] + + proxy_id: str = FieldInfo(alias="proxyId") + + user: str diff --git a/src/mobilerun_sdk/types/shared_params/__init__.py b/src/mobilerun_sdk/types/shared_params/__init__.py index 0b4dbfbb..8f3c07f4 100644 --- a/src/mobilerun_sdk/types/shared_params/__init__.py +++ b/src/mobilerun_sdk/types/shared_params/__init__.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .socks5 import Socks5 as Socks5 from .location import Location as Location from .device_spec import DeviceSpec as DeviceSpec from .device_carrier import DeviceCarrier as DeviceCarrier diff --git a/src/mobilerun_sdk/types/shared_params/device_spec.py b/src/mobilerun_sdk/types/shared_params/device_spec.py index 1f919724..fe115fd4 100644 --- a/src/mobilerun_sdk/types/shared_params/device_spec.py +++ b/src/mobilerun_sdk/types/shared_params/device_spec.py @@ -3,16 +3,15 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Annotated, TypedDict +from typing_extensions import Required, Annotated, TypedDict -from .socks5 import Socks5 from ..._types import SequenceNotStr from ..._utils import PropertyInfo from .location import Location from .device_carrier import DeviceCarrier from .device_identifiers import DeviceIdentifiers -__all__ = ["DeviceSpec", "Proxy", "ProxyConnect"] +__all__ = ["DeviceSpec", "Proxy", "ProxyConnect", "ProxySocks5"] class ProxyConnect(TypedDict, total=False): @@ -26,6 +25,16 @@ class ProxyConnect(TypedDict, total=False): """ +class ProxySocks5(TypedDict, total=False): + host: Required[str] + + password: Required[str] + + port: Required[int] + + user: Required[str] + + class Proxy(TypedDict, total=False): connect: ProxyConnect @@ -33,7 +42,7 @@ class Proxy(TypedDict, total=False): smart_ip: Annotated[bool, PropertyInfo(alias="smartIp")] - socks5: Socks5 + socks5: ProxySocks5 class DeviceSpec(TypedDict, total=False): diff --git a/src/mobilerun_sdk/types/shared_params/socks5.py b/src/mobilerun_sdk/types/shared_params/socks5.py deleted file mode 100644 index 0e56d16b..00000000 --- a/src/mobilerun_sdk/types/shared_params/socks5.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, TypedDict - -__all__ = ["Socks5"] - - -class Socks5(TypedDict, total=False): - host: Required[str] - - password: Required[str] - - port: Required[int] - - user: Required[str] diff --git a/src/mobilerun_sdk/types/store/__init__.py b/src/mobilerun_sdk/types/store/__init__.py new file mode 100644 index 00000000..b1a55b52 --- /dev/null +++ b/src/mobilerun_sdk/types/store/__init__.py @@ -0,0 +1,8 @@ +# 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 .app_list_response import AppListResponse as AppListResponse +from .app_retrieve_response import AppRetrieveResponse as AppRetrieveResponse +from .app_add_to_workspace_response import AppAddToWorkspaceResponse as AppAddToWorkspaceResponse diff --git a/src/mobilerun_sdk/types/store/app_add_to_workspace_response.py b/src/mobilerun_sdk/types/store/app_add_to_workspace_response.py new file mode 100644 index 00000000..81a93517 --- /dev/null +++ b/src/mobilerun_sdk/types/store/app_add_to_workspace_response.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AppAddToWorkspaceResponse"] + + +class AppAddToWorkspaceResponse(BaseModel): + message: str + + success: Literal[True] diff --git a/src/mobilerun_sdk/types/store/app_list_params.py b/src/mobilerun_sdk/types/store/app_list_params.py new file mode 100644 index 00000000..5451fcea --- /dev/null +++ b/src/mobilerun_sdk/types/store/app_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 Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["AppListParams"] + + +class AppListParams(TypedDict, total=False): + category: str + + page: int + + page_size: Annotated[int, PropertyInfo(alias="pageSize")] + + query: str diff --git a/src/mobilerun_sdk/types/store/app_list_response.py b/src/mobilerun_sdk/types/store/app_list_response.py new file mode 100644 index 00000000..7ee43700 --- /dev/null +++ b/src/mobilerun_sdk/types/store/app_list_response.py @@ -0,0 +1,330 @@ +# 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 ..shared.pagination import Pagination + +__all__ = ["AppListResponse", "Item", "ItemVersion"] + + +class ItemVersion(BaseModel): + id: str + + app_id: str = FieldInfo(alias="appId") + + country: Literal[ + "AF", + "AL", + "DZ", + "AS", + "AD", + "AO", + "AI", + "AQ", + "AG", + "AR", + "AM", + "AW", + "AP", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BY", + "BE", + "BZ", + "BJ", + "BM", + "BT", + "BO", + "BQ", + "BA", + "BW", + "BV", + "BR", + "IO", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "KY", + "CF", + "TD", + "CL", + "CN", + "CX", + "CC", + "CO", + "KM", + "CG", + "CD", + "CK", + "CR", + "HR", + "CU", + "CW", + "CY", + "CZ", + "CI", + "DK", + "DJ", + "DM", + "DO", + "EC", + "EG", + "SV", + "GQ", + "ER", + "EE", + "ET", + "FK", + "FO", + "FJ", + "FI", + "FR", + "GF", + "PF", + "TF", + "GA", + "GM", + "GE", + "DE", + "GH", + "GI", + "GR", + "GL", + "GD", + "GP", + "GU", + "GT", + "GG", + "GN", + "GW", + "GY", + "HT", + "HM", + "VA", + "HN", + "HK", + "HU", + "IS", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IM", + "IL", + "IT", + "JM", + "JP", + "JE", + "JO", + "KZ", + "KE", + "KI", + "KR", + "KW", + "KG", + "LA", + "LV", + "LB", + "LS", + "LR", + "LY", + "LI", + "LT", + "LU", + "MO", + "MG", + "MW", + "MY", + "MV", + "ML", + "MT", + "MH", + "MQ", + "MR", + "MU", + "YT", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MS", + "MA", + "MZ", + "MM", + "NA", + "NR", + "NP", + "NL", + "AN", + "NC", + "NZ", + "NI", + "NE", + "NG", + "NU", + "NF", + "KP", + "MK", + "MP", + "NO", + "OM", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "PE", + "PH", + "PN", + "PL", + "PT", + "PR", + "QA", + "RE", + "RO", + "RU", + "RW", + "BL", + "SH", + "KN", + "LC", + "MF", + "PM", + "VC", + "WS", + "SM", + "ST", + "SA", + "SN", + "RS", + "CS", + "SC", + "SL", + "SG", + "SX", + "SK", + "SI", + "SB", + "SO", + "ZA", + "GS", + "SS", + "ES", + "LK", + "SD", + "SR", + "SJ", + "SZ", + "SE", + "CH", + "SY", + "TW", + "TJ", + "TZ", + "TH", + "TL", + "TG", + "TK", + "TO", + "TT", + "TN", + "TR", + "TM", + "TC", + "TV", + "UG", + "UA", + "AE", + "GB", + "US", + "UM", + "UY", + "UZ", + "VU", + "VE", + "VN", + "VG", + "VI", + "WF", + "EH", + "YE", + "ZM", + "ZW", + "AX", + ] + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + queued_at: Optional[datetime] = FieldInfo(alias="queuedAt", default=None) + + size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None) + + source: Literal["user", "system", "portal", "store"] + + status: Literal["queued", "available", "failed"] + + target_sdk: Optional[int] = FieldInfo(alias="targetSdk", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + version_code: int = FieldInfo(alias="versionCode") + + version_name: str = FieldInfo(alias="versionName") + + +class Item(BaseModel): + id: str + + bundle_id: str = FieldInfo(alias="bundleId") + + category: Optional[str] = None + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + description: Optional[str] = None + + developer_name: Optional[str] = FieldInfo(alias="developerName", default=None) + + display_name: str = FieldInfo(alias="displayName") + + featured: bool + + icon_url: str = FieldInfo(alias="iconURL") + + platform: Literal["android", "ios"] + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + version: ItemVersion + + +class AppListResponse(BaseModel): + items: List[Item] + + pagination: Pagination diff --git a/src/mobilerun_sdk/types/store/app_retrieve_response.py b/src/mobilerun_sdk/types/store/app_retrieve_response.py new file mode 100644 index 00000000..a8cff78c --- /dev/null +++ b/src/mobilerun_sdk/types/store/app_retrieve_response.py @@ -0,0 +1,329 @@ +# 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 + +__all__ = ["AppRetrieveResponse", "Data", "DataVersion"] + + +class DataVersion(BaseModel): + id: str + + app_id: str = FieldInfo(alias="appId") + + country: Literal[ + "AF", + "AL", + "DZ", + "AS", + "AD", + "AO", + "AI", + "AQ", + "AG", + "AR", + "AM", + "AW", + "AP", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BY", + "BE", + "BZ", + "BJ", + "BM", + "BT", + "BO", + "BQ", + "BA", + "BW", + "BV", + "BR", + "IO", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "KY", + "CF", + "TD", + "CL", + "CN", + "CX", + "CC", + "CO", + "KM", + "CG", + "CD", + "CK", + "CR", + "HR", + "CU", + "CW", + "CY", + "CZ", + "CI", + "DK", + "DJ", + "DM", + "DO", + "EC", + "EG", + "SV", + "GQ", + "ER", + "EE", + "ET", + "FK", + "FO", + "FJ", + "FI", + "FR", + "GF", + "PF", + "TF", + "GA", + "GM", + "GE", + "DE", + "GH", + "GI", + "GR", + "GL", + "GD", + "GP", + "GU", + "GT", + "GG", + "GN", + "GW", + "GY", + "HT", + "HM", + "VA", + "HN", + "HK", + "HU", + "IS", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IM", + "IL", + "IT", + "JM", + "JP", + "JE", + "JO", + "KZ", + "KE", + "KI", + "KR", + "KW", + "KG", + "LA", + "LV", + "LB", + "LS", + "LR", + "LY", + "LI", + "LT", + "LU", + "MO", + "MG", + "MW", + "MY", + "MV", + "ML", + "MT", + "MH", + "MQ", + "MR", + "MU", + "YT", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MS", + "MA", + "MZ", + "MM", + "NA", + "NR", + "NP", + "NL", + "AN", + "NC", + "NZ", + "NI", + "NE", + "NG", + "NU", + "NF", + "KP", + "MK", + "MP", + "NO", + "OM", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "PE", + "PH", + "PN", + "PL", + "PT", + "PR", + "QA", + "RE", + "RO", + "RU", + "RW", + "BL", + "SH", + "KN", + "LC", + "MF", + "PM", + "VC", + "WS", + "SM", + "ST", + "SA", + "SN", + "RS", + "CS", + "SC", + "SL", + "SG", + "SX", + "SK", + "SI", + "SB", + "SO", + "ZA", + "GS", + "SS", + "ES", + "LK", + "SD", + "SR", + "SJ", + "SZ", + "SE", + "CH", + "SY", + "TW", + "TJ", + "TZ", + "TH", + "TL", + "TG", + "TK", + "TO", + "TT", + "TN", + "TR", + "TM", + "TC", + "TV", + "UG", + "UA", + "AE", + "GB", + "US", + "UM", + "UY", + "UZ", + "VU", + "VE", + "VN", + "VG", + "VI", + "WF", + "EH", + "YE", + "ZM", + "ZW", + "AX", + ] + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + owner_id: Optional[str] = FieldInfo(alias="ownerId", default=None) + + queued_at: Optional[datetime] = FieldInfo(alias="queuedAt", default=None) + + size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None) + + source: Literal["user", "system", "portal", "store"] + + status: Literal["queued", "available", "failed"] + + target_sdk: Optional[int] = FieldInfo(alias="targetSdk", default=None) + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + user_id: Optional[str] = FieldInfo(alias="userId", default=None) + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + version_code: int = FieldInfo(alias="versionCode") + + version_name: str = FieldInfo(alias="versionName") + + +class Data(BaseModel): + id: str + + bundle_id: str = FieldInfo(alias="bundleId") + + category: Optional[str] = None + + created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) + + description: Optional[str] = None + + developer_name: Optional[str] = FieldInfo(alias="developerName", default=None) + + display_name: str = FieldInfo(alias="displayName") + + featured: bool + + icon_url: str = FieldInfo(alias="iconURL") + + platform: Literal["android", "ios"] + + screenshot_urls: List[str] = FieldInfo(alias="screenshotUrls") + + updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) + + version: DataVersion + + +class AppRetrieveResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/store_categories_response.py b/src/mobilerun_sdk/types/store_categories_response.py new file mode 100644 index 00000000..b919225b --- /dev/null +++ b/src/mobilerun_sdk/types/store_categories_response.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List + +from .._models import BaseModel + +__all__ = ["StoreCategoriesResponse"] + + +class StoreCategoriesResponse(BaseModel): + categories: List[str] diff --git a/src/mobilerun_sdk/types/task.py b/src/mobilerun_sdk/types/task.py deleted file mode 100644 index 74fceef4..00000000 --- a/src/mobilerun_sdk/types/task.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["Task"] - - -class Task(BaseModel): - created_at: datetime = FieldInfo(alias="createdAt") - - task_id: str = FieldInfo(alias="taskId") - - updated_at: datetime = FieldInfo(alias="updatedAt") diff --git a/src/mobilerun_sdk/types/task_get_status_response.py b/src/mobilerun_sdk/types/task_get_status_response.py index e803179e..4446b3bb 100644 --- a/src/mobilerun_sdk/types/task_get_status_response.py +++ b/src/mobilerun_sdk/types/task_get_status_response.py @@ -6,7 +6,6 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .task_status import TaskStatus __all__ = ["TaskGetStatusResponse", "Execution", "ExecutionCheckpoint"] @@ -34,7 +33,7 @@ class Execution(BaseModel): class TaskGetStatusResponse(BaseModel): - status: TaskStatus + status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] """The status of the task""" execution: Optional[Execution] = None diff --git a/src/mobilerun_sdk/types/task_get_trajectory_response.py b/src/mobilerun_sdk/types/task_get_trajectory_response.py index 0405cf9a..b078d881 100644 --- a/src/mobilerun_sdk/types/task_get_trajectory_response.py +++ b/src/mobilerun_sdk/types/task_get_trajectory_response.py @@ -6,7 +6,6 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .usage_result import UsageResult __all__ = [ "TaskGetTrajectoryResponse", @@ -37,6 +36,7 @@ "TrajectoryTrajectoryFastAgentInputEvent", "TrajectoryTrajectoryFastAgentResponseEvent", "TrajectoryTrajectoryFastAgentResponseEventData", + "TrajectoryTrajectoryFastAgentResponseEventDataUsage", "TrajectoryTrajectoryFastAgentToolCallEvent", "TrajectoryTrajectoryFastAgentToolCallEventData", "TrajectoryTrajectoryFastAgentOutputEvent", @@ -54,12 +54,14 @@ "TrajectoryTrajectoryManagerContextEvent", "TrajectoryTrajectoryManagerResponseEvent", "TrajectoryTrajectoryManagerResponseEventData", + "TrajectoryTrajectoryManagerResponseEventDataUsage", "TrajectoryTrajectoryManagerPlanDetailsEvent", "TrajectoryTrajectoryManagerPlanDetailsEventData", "TrajectoryTrajectoryExecutorContextEvent", "TrajectoryTrajectoryExecutorContextEventData", "TrajectoryTrajectoryExecutorResponseEvent", "TrajectoryTrajectoryExecutorResponseEventData", + "TrajectoryTrajectoryExecutorResponseEventDataUsage", "TrajectoryTrajectoryExecutorActionEvent", "TrajectoryTrajectoryExecutorActionEventData", "TrajectoryTrajectoryExecutorActionResultEvent", @@ -279,6 +281,16 @@ class TrajectoryTrajectoryFastAgentInputEvent(BaseModel): event: Literal["FastAgentInputEvent"] +class TrajectoryTrajectoryFastAgentResponseEventDataUsage(BaseModel): + request_tokens: int + + requests: int + + response_tokens: int + + total_tokens: int + + class TrajectoryTrajectoryFastAgentResponseEventData(BaseModel): """LLM response received.""" @@ -286,7 +298,7 @@ class TrajectoryTrajectoryFastAgentResponseEventData(BaseModel): code: Optional[str] = None - usage: Optional[UsageResult] = None + usage: Optional[TrajectoryTrajectoryFastAgentResponseEventDataUsage] = None class TrajectoryTrajectoryFastAgentResponseEvent(BaseModel): @@ -401,12 +413,22 @@ class TrajectoryTrajectoryManagerContextEvent(BaseModel): event: Literal["ManagerContextEvent"] +class TrajectoryTrajectoryManagerResponseEventDataUsage(BaseModel): + request_tokens: int + + requests: int + + response_tokens: int + + total_tokens: int + + class TrajectoryTrajectoryManagerResponseEventData(BaseModel): """LLM response received, ready for parsing.""" response: str - usage: Optional[UsageResult] = None + usage: Optional[TrajectoryTrajectoryManagerResponseEventDataUsage] = None class TrajectoryTrajectoryManagerResponseEvent(BaseModel): @@ -456,12 +478,22 @@ class TrajectoryTrajectoryExecutorContextEvent(BaseModel): event: Literal["ExecutorContextEvent"] +class TrajectoryTrajectoryExecutorResponseEventDataUsage(BaseModel): + request_tokens: int + + requests: int + + response_tokens: int + + total_tokens: int + + class TrajectoryTrajectoryExecutorResponseEventData(BaseModel): """LLM response received, ready for parsing.""" response: str - usage: Optional[UsageResult] = None + usage: Optional[TrajectoryTrajectoryExecutorResponseEventDataUsage] = None class TrajectoryTrajectoryExecutorResponseEvent(BaseModel): diff --git a/src/mobilerun_sdk/types/task_list_params.py b/src/mobilerun_sdk/types/task_list_params.py index ba5364e7..044f84ad 100644 --- a/src/mobilerun_sdk/types/task_list_params.py +++ b/src/mobilerun_sdk/types/task_list_params.py @@ -6,7 +6,6 @@ from typing_extensions import Literal, Annotated, TypedDict from .._utils import PropertyInfo -from .task_status import TaskStatus __all__ = ["TaskListParams"] @@ -29,4 +28,4 @@ class TaskListParams(TypedDict, total=False): query: Optional[str] """Search in task description.""" - status: Optional[TaskStatus] + status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] diff --git a/src/mobilerun_sdk/types/task_list_response.py b/src/mobilerun_sdk/types/task_list_response.py index 61139fb7..20a9744c 100644 --- a/src/mobilerun_sdk/types/task_list_response.py +++ b/src/mobilerun_sdk/types/task_list_response.py @@ -7,11 +7,15 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .task_status import TaskStatus -from .package_credentials import PackageCredentials from .shared.pagination_meta import PaginationMeta -__all__ = ["TaskListResponse", "Item"] +__all__ = ["TaskListResponse", "Item", "ItemCredential"] + + +class ItemCredential(BaseModel): + credential_names: List[str] = FieldInfo(alias="credentialNames") + + package_name: str = FieldInfo(alias="packageName") class Item(BaseModel): @@ -28,7 +32,7 @@ class Item(BaseModel): owner_id: str = FieldInfo(alias="ownerId") - status: TaskStatus + status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] task: str @@ -53,7 +57,7 @@ class Item(BaseModel): created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - credentials: Optional[List[PackageCredentials]] = None + credentials: Optional[List[ItemCredential]] = None credits_used: Optional[float] = FieldInfo(alias="creditsUsed", default=None) diff --git a/src/mobilerun_sdk/types/task_retrieve_response.py b/src/mobilerun_sdk/types/task_retrieve_response.py index a2ffcf60..85887f56 100644 --- a/src/mobilerun_sdk/types/task_retrieve_response.py +++ b/src/mobilerun_sdk/types/task_retrieve_response.py @@ -7,10 +7,14 @@ from pydantic import Field as FieldInfo from .._models import BaseModel -from .task_status import TaskStatus -from .package_credentials import PackageCredentials -__all__ = ["TaskRetrieveResponse", "Task"] +__all__ = ["TaskRetrieveResponse", "Task", "TaskCredential"] + + +class TaskCredential(BaseModel): + credential_names: List[str] = FieldInfo(alias="credentialNames") + + package_name: str = FieldInfo(alias="packageName") class Task(BaseModel): @@ -27,7 +31,7 @@ class Task(BaseModel): owner_id: str = FieldInfo(alias="ownerId") - status: TaskStatus + status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] task: str @@ -52,7 +56,7 @@ class Task(BaseModel): created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - credentials: Optional[List[PackageCredentials]] = None + credentials: Optional[List[TaskCredential]] = None credits_used: Optional[float] = FieldInfo(alias="creditsUsed", default=None) diff --git a/src/mobilerun_sdk/types/task_run_params.py b/src/mobilerun_sdk/types/task_run_params.py index c403374b..b66cf98f 100644 --- a/src/mobilerun_sdk/types/task_run_params.py +++ b/src/mobilerun_sdk/types/task_run_params.py @@ -7,9 +7,8 @@ from .._types import SequenceNotStr from .._utils import PropertyInfo -from .package_credentials_param import PackageCredentialsParam -__all__ = ["TaskRunParams"] +__all__ = ["TaskRunParams", "Credential"] class TaskRunParams(TypedDict, total=False): @@ -26,7 +25,7 @@ class TaskRunParams(TypedDict, total=False): continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")] - credentials: Iterable[PackageCredentialsParam] + credentials: Iterable[Credential] display_id: Annotated[int, PropertyInfo(alias="displayId")] """The display ID of the device to run the task on.""" @@ -61,3 +60,9 @@ class TaskRunParams(TypedDict, total=False): ] idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] + + +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/src/mobilerun_sdk/types/task_run_response.py b/src/mobilerun_sdk/types/task_run_response.py index bc0dfe32..5987ba3d 100644 --- a/src/mobilerun_sdk/types/task_run_response.py +++ b/src/mobilerun_sdk/types/task_run_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import Optional +from typing_extensions import Literal from pydantic import Field as FieldInfo from .._models import BaseModel -from .task_status import TaskStatus __all__ = ["TaskRunResponse"] @@ -14,7 +14,7 @@ class TaskRunResponse(BaseModel): id: str """The ID of the task""" - status: TaskStatus + status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] """The status of the task (queued or created)""" stream_url: Optional[str] = FieldInfo(alias="streamUrl", default=None) diff --git a/src/mobilerun_sdk/types/task_run_streamed_params.py b/src/mobilerun_sdk/types/task_run_streamed_params.py index ab4ada19..2522d16b 100644 --- a/src/mobilerun_sdk/types/task_run_streamed_params.py +++ b/src/mobilerun_sdk/types/task_run_streamed_params.py @@ -7,9 +7,8 @@ from .._types import SequenceNotStr from .._utils import PropertyInfo -from .package_credentials_param import PackageCredentialsParam -__all__ = ["TaskRunStreamedParams"] +__all__ = ["TaskRunStreamedParams", "Credential"] class TaskRunStreamedParams(TypedDict, total=False): @@ -26,7 +25,7 @@ class TaskRunStreamedParams(TypedDict, total=False): continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")] - credentials: Iterable[PackageCredentialsParam] + credentials: Iterable[Credential] display_id: Annotated[int, PropertyInfo(alias="displayId")] """The display ID of the device to run the task on.""" @@ -59,3 +58,9 @@ class TaskRunStreamedParams(TypedDict, total=False): 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/src/mobilerun_sdk/types/task_status.py b/src/mobilerun_sdk/types/task_status.py deleted file mode 100644 index 2449cab8..00000000 --- a/src/mobilerun_sdk/types/task_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["TaskStatus"] - -TaskStatus: TypeAlias = Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] diff --git a/src/mobilerun_sdk/types/tasks/__init__.py b/src/mobilerun_sdk/types/tasks/__init__.py index 892f5189..3039c6c4 100644 --- a/src/mobilerun_sdk/types/tasks/__init__.py +++ b/src/mobilerun_sdk/types/tasks/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations -from .media_response import MediaResponse as MediaResponse from .ui_state_list_response import UiStateListResponse as UiStateListResponse from .screenshot_list_response import ScreenshotListResponse as ScreenshotListResponse +from .ui_state_retrieve_response import UiStateRetrieveResponse as UiStateRetrieveResponse +from .screenshot_retrieve_response import ScreenshotRetrieveResponse as ScreenshotRetrieveResponse diff --git a/src/mobilerun_sdk/types/tasks/screenshot_retrieve_response.py b/src/mobilerun_sdk/types/tasks/screenshot_retrieve_response.py new file mode 100644 index 00000000..d8ccef61 --- /dev/null +++ b/src/mobilerun_sdk/types/tasks/screenshot_retrieve_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["ScreenshotRetrieveResponse"] + + +class ScreenshotRetrieveResponse(BaseModel): + url: str + """The URL of the media""" diff --git a/src/mobilerun_sdk/types/tasks/media_response.py b/src/mobilerun_sdk/types/tasks/ui_state_retrieve_response.py similarity index 67% rename from src/mobilerun_sdk/types/tasks/media_response.py rename to src/mobilerun_sdk/types/tasks/ui_state_retrieve_response.py index 0a5af44a..f5993bf4 100644 --- a/src/mobilerun_sdk/types/tasks/media_response.py +++ b/src/mobilerun_sdk/types/tasks/ui_state_retrieve_response.py @@ -2,9 +2,9 @@ from ..._models import BaseModel -__all__ = ["MediaResponse"] +__all__ = ["UiStateRetrieveResponse"] -class MediaResponse(BaseModel): +class UiStateRetrieveResponse(BaseModel): url: str """The URL of the media""" diff --git a/src/mobilerun_sdk/types/usage_result.py b/src/mobilerun_sdk/types/usage_result.py deleted file mode 100644 index c80ba912..00000000 --- a/src/mobilerun_sdk/types/usage_result.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["UsageResult"] - - -class UsageResult(BaseModel): - request_tokens: int - - requests: int - - response_tokens: int - - total_tokens: int diff --git a/src/mobilerun_sdk/types/workflows/__init__.py b/src/mobilerun_sdk/types/workflows/__init__.py index 860c6eb8..d9ae0f73 100644 --- a/src/mobilerun_sdk/types/workflows/__init__.py +++ b/src/mobilerun_sdk/types/workflows/__init__.py @@ -2,8 +2,6 @@ from __future__ import annotations -from .action import Action as Action -from .flow_execution import FlowExecution as FlowExecution from .flow_list_params import FlowListParams as FlowListParams from .flow_clone_params import FlowCloneParams as FlowCloneParams from .action_list_params import ActionListParams as ActionListParams @@ -12,9 +10,9 @@ from .flow_update_params import FlowUpdateParams as FlowUpdateParams from .event_ingest_params import EventIngestParams as EventIngestParams from .flow_clone_response import FlowCloneResponse as FlowCloneResponse +from .flow_dry_run_params import FlowDryRunParams as FlowDryRunParams from .trigger_fire_params import TriggerFireParams as TriggerFireParams from .trigger_list_params import TriggerListParams as TriggerListParams -from .action_catalog_entry import ActionCatalogEntry as ActionCatalogEntry from .action_create_params import ActionCreateParams as ActionCreateParams from .action_list_response import ActionListResponse as ActionListResponse from .action_update_params import ActionUpdateParams as ActionUpdateParams @@ -24,6 +22,7 @@ from .flow_update_response import FlowUpdateResponse as FlowUpdateResponse from .event_ingest_response import EventIngestResponse as EventIngestResponse from .execution_list_params import ExecutionListParams as ExecutionListParams +from .flow_dry_run_response import FlowDryRunResponse as FlowDryRunResponse from .flow_unblock_response import FlowUnblockResponse as FlowUnblockResponse from .trigger_create_params import TriggerCreateParams as TriggerCreateParams from .trigger_fire_response import TriggerFireResponse as TriggerFireResponse @@ -40,12 +39,12 @@ from .trigger_delete_response import TriggerDeleteResponse as TriggerDeleteResponse from .trigger_update_response import TriggerUpdateResponse as TriggerUpdateResponse from .action_retrieve_response import ActionRetrieveResponse as ActionRetrieveResponse +from .execution_abort_response import ExecutionAbortResponse as ExecutionAbortResponse from .trigger_retrieve_response import TriggerRetrieveResponse as TriggerRetrieveResponse from .action_catalog_list_params import ActionCatalogListParams as ActionCatalogListParams +from .flow_list_repairs_response import FlowListRepairsResponse as FlowListRepairsResponse from .execution_retrieve_response import ExecutionRetrieveResponse as ExecutionRetrieveResponse -from .flow_action_overrides_param import FlowActionOverridesParam as FlowActionOverridesParam from .action_catalog_list_response import ActionCatalogListResponse as ActionCatalogListResponse from .execution_get_metrics_params import ExecutionGetMetricsParams as ExecutionGetMetricsParams -from .flow_child_action_input_param import FlowChildActionInputParam as FlowChildActionInputParam from .execution_get_metrics_response import ExecutionGetMetricsResponse as ExecutionGetMetricsResponse from .action_catalog_retrieve_response import ActionCatalogRetrieveResponse as ActionCatalogRetrieveResponse diff --git a/src/mobilerun_sdk/types/workflows/action.py b/src/mobilerun_sdk/types/workflows/action.py deleted file mode 100644 index 2eabf094..00000000 --- a/src/mobilerun_sdk/types/workflows/action.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["Action"] - - -class Action(BaseModel): - id: str - - catalog_entry_id: str = FieldInfo(alias="catalogEntryId") - - created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - description: Optional[str] = None - - method: str - - name: str - - owner_id: str = FieldInfo(alias="ownerId") - - service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] - - updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) - - user_id: str = FieldInfo(alias="userId") - """Deprecated: use ownerId (tenancy) / createdBy (actor).""" - - params: Optional[object] = None - - params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) diff --git a/src/mobilerun_sdk/types/workflows/action_catalog_entry.py b/src/mobilerun_sdk/types/workflows/action_catalog_entry.py deleted file mode 100644 index 5e6278c2..00000000 --- a/src/mobilerun_sdk/types/workflows/action_catalog_entry.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["ActionCatalogEntry"] - - -class ActionCatalogEntry(BaseModel): - id: str - - created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) - - description: Optional[str] = None - - method: str - - name: str - - service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] - - updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) - - params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) diff --git a/src/mobilerun_sdk/types/workflows/action_catalog_list_response.py b/src/mobilerun_sdk/types/workflows/action_catalog_list_response.py index 967cfd08..231b0240 100644 --- a/src/mobilerun_sdk/types/workflows/action_catalog_list_response.py +++ b/src/mobilerun_sdk/types/workflows/action_catalog_list_response.py @@ -1,15 +1,35 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo from ..._models import BaseModel from ..shared.pagination import Pagination -from .action_catalog_entry import ActionCatalogEntry -__all__ = ["ActionCatalogListResponse"] +__all__ = ["ActionCatalogListResponse", "Item"] + + +class Item(BaseModel): + id: str + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + description: Optional[str] = None + + method: str + + name: str + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionCatalogListResponse(BaseModel): - items: List[ActionCatalogEntry] + items: List[Item] pagination: Pagination diff --git a/src/mobilerun_sdk/types/workflows/action_catalog_retrieve_response.py b/src/mobilerun_sdk/types/workflows/action_catalog_retrieve_response.py index 81d1b5f0..8769f574 100644 --- a/src/mobilerun_sdk/types/workflows/action_catalog_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/action_catalog_retrieve_response.py @@ -1,10 +1,32 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -from .action_catalog_entry import ActionCatalogEntry -__all__ = ["ActionCatalogRetrieveResponse"] +__all__ = ["ActionCatalogRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + description: Optional[str] = None + + method: str + + name: str + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionCatalogRetrieveResponse(BaseModel): - data: ActionCatalogEntry + data: Data diff --git a/src/mobilerun_sdk/types/workflows/action_create_response.py b/src/mobilerun_sdk/types/workflows/action_create_response.py index acd7aa54..3a44b0a6 100644 --- a/src/mobilerun_sdk/types/workflows/action_create_response.py +++ b/src/mobilerun_sdk/types/workflows/action_create_response.py @@ -1,10 +1,43 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .action import Action +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["ActionCreateResponse"] +__all__ = ["ActionCreateResponse", "Data"] + + +class Data(BaseModel): + id: str + + catalog_entry_id: str = FieldInfo(alias="catalogEntryId") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + method: str + + name: str + + owner_id: str = FieldInfo(alias="ownerId") + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + params: Optional[object] = None + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionCreateResponse(BaseModel): - data: Action + data: Data diff --git a/src/mobilerun_sdk/types/workflows/action_list_response.py b/src/mobilerun_sdk/types/workflows/action_list_response.py index 2d5e996e..9fc8ce86 100644 --- a/src/mobilerun_sdk/types/workflows/action_list_response.py +++ b/src/mobilerun_sdk/types/workflows/action_list_response.py @@ -1,15 +1,46 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo -from .action import Action from ..._models import BaseModel from ..shared.pagination import Pagination -__all__ = ["ActionListResponse"] +__all__ = ["ActionListResponse", "Item"] + + +class Item(BaseModel): + id: str + + catalog_entry_id: str = FieldInfo(alias="catalogEntryId") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + method: str + + name: str + + owner_id: str = FieldInfo(alias="ownerId") + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + params: Optional[object] = None + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionListResponse(BaseModel): - items: List[Action] + items: List[Item] pagination: Pagination diff --git a/src/mobilerun_sdk/types/workflows/action_retrieve_response.py b/src/mobilerun_sdk/types/workflows/action_retrieve_response.py index 7dc33b01..61d45f65 100644 --- a/src/mobilerun_sdk/types/workflows/action_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/action_retrieve_response.py @@ -1,10 +1,43 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .action import Action +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["ActionRetrieveResponse"] +__all__ = ["ActionRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + catalog_entry_id: str = FieldInfo(alias="catalogEntryId") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + method: str + + name: str + + owner_id: str = FieldInfo(alias="ownerId") + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + params: Optional[object] = None + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionRetrieveResponse(BaseModel): - data: Action + data: Data diff --git a/src/mobilerun_sdk/types/workflows/action_update_response.py b/src/mobilerun_sdk/types/workflows/action_update_response.py index 4d6b872f..1b5a53b4 100644 --- a/src/mobilerun_sdk/types/workflows/action_update_response.py +++ b/src/mobilerun_sdk/types/workflows/action_update_response.py @@ -1,10 +1,43 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .action import Action +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["ActionUpdateResponse"] +__all__ = ["ActionUpdateResponse", "Data"] + + +class Data(BaseModel): + id: str + + catalog_entry_id: str = FieldInfo(alias="catalogEntryId") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + method: str + + name: str + + owner_id: str = FieldInfo(alias="ownerId") + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + params: Optional[object] = None + + params_schema: Optional[object] = FieldInfo(alias="paramsSchema", default=None) class ActionUpdateResponse(BaseModel): - data: Action + data: Data diff --git a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py index c091dfa8..c3509640 100644 --- a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py +++ b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py @@ -5,7 +5,6 @@ from pydantic import Field as FieldInfo -from ..flow import Flow from ..._models import BaseModel __all__ = [ @@ -13,6 +12,7 @@ "Data", "DataMatchedFlow", "DataMatchedFlowAction", + "DataMatchedFlowFlow", "DataMatchedFlowGates", "DataMatchedFlowTrigger", "DataValidation", @@ -38,6 +38,69 @@ class DataMatchedFlowAction(BaseModel): params: Optional[Dict[str, object]] = None +class DataMatchedFlowFlow(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" + + class DataMatchedFlowGates(BaseModel): blocked: bool @@ -86,7 +149,7 @@ class DataMatchedFlowTrigger(BaseModel): class DataMatchedFlow(BaseModel): actions: List[DataMatchedFlowAction] - flow: Flow + flow: DataMatchedFlowFlow gates: DataMatchedFlowGates diff --git a/src/mobilerun_sdk/types/workflows/flow_execution.py b/src/mobilerun_sdk/types/workflows/execution_abort_response.py similarity index 91% rename from src/mobilerun_sdk/types/workflows/flow_execution.py rename to src/mobilerun_sdk/types/workflows/execution_abort_response.py index 27d99104..853122f0 100644 --- a/src/mobilerun_sdk/types/workflows/flow_execution.py +++ b/src/mobilerun_sdk/types/workflows/execution_abort_response.py @@ -7,10 +7,10 @@ from ..._models import BaseModel -__all__ = ["FlowExecution"] +__all__ = ["ExecutionAbortResponse", "Data"] -class FlowExecution(BaseModel): +class Data(BaseModel): id: str error: Optional[str] = None @@ -42,3 +42,7 @@ class FlowExecution(BaseModel): success/failed/stopped, see deriveStepStatus); it is optional and absent on legacy blob-only executions, so clients must not assume its presence. """ + + +class ExecutionAbortResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/workflows/execution_list_response.py b/src/mobilerun_sdk/types/workflows/execution_list_response.py index 094d7a9d..93c5a45c 100644 --- a/src/mobilerun_sdk/types/workflows/execution_list_response.py +++ b/src/mobilerun_sdk/types/workflows/execution_list_response.py @@ -1,19 +1,51 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional +from typing_extensions import Literal from pydantic import Field as FieldInfo from ..._models import BaseModel -from .flow_execution import FlowExecution from ..shared.pagination import Pagination __all__ = ["ExecutionListResponse", "Item"] -class Item(FlowExecution): +class Item(BaseModel): + id: str + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + error: Optional[str] = None + + event_id: Optional[str] = FieldInfo(alias="eventId", default=None) + + finished_at: Optional[str] = FieldInfo(alias="finishedAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + flow_name: Optional[str] = FieldInfo(alias="flowName", default=None) + + kind: Literal["live", "dry_run"] + + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) + + status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None + + trigger_id: str = FieldInfo(alias="triggerId") + + trigger_name: Optional[str] = FieldInfo(alias="triggerName", default=None) + + result: Optional[object] = None + """Opaque per-step result blob ({ steps: [...] }). + + Each step additionally carries a `verdict` field ({ outcome, summary, reason? } + | null) when it is an agent.run step that opted into a verdict — null otherwise. + Table-backed steps (current executions) also carry a `status` string (e.g. + success/failed/stopped, see deriveStepStatus); it is optional and absent on + legacy blob-only executions, so clients must not assume its presence. + """ + class ExecutionListResponse(BaseModel): items: List[Item] diff --git a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py index 0f9b7815..d67a8f4f 100644 --- a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py @@ -1,11 +1,11 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from typing import List, Optional +from typing_extensions import Literal from pydantic import Field as FieldInfo from ..._models import BaseModel -from .flow_execution import FlowExecution __all__ = ["ExecutionRetrieveResponse", "Data", "DataFile"] @@ -20,9 +20,15 @@ class DataFile(BaseModel): size_bytes: int = FieldInfo(alias="sizeBytes") -class Data(FlowExecution): +class Data(BaseModel): + id: str + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + error: Optional[str] = None + + event_id: Optional[str] = FieldInfo(alias="eventId", default=None) + files: List[DataFile] """ Files produced by files.upload steps, plus files an agent.run step reported on @@ -30,6 +36,32 @@ class Data(FlowExecution): the turn); derived server-side at read time. """ + finished_at: Optional[str] = FieldInfo(alias="finishedAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + flow_name: Optional[str] = FieldInfo(alias="flowName", default=None) + + kind: Literal["live", "dry_run"] + + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) + + status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None + + trigger_id: str = FieldInfo(alias="triggerId") + + trigger_name: Optional[str] = FieldInfo(alias="triggerName", default=None) + + result: Optional[object] = None + """Opaque per-step result blob ({ steps: [...] }). + + Each step additionally carries a `verdict` field ({ outcome, summary, reason? } + | null) when it is an agent.run step that opted into a verdict — null otherwise. + Table-backed steps (current executions) also carry a `status` string (e.g. + success/failed/stopped, see deriveStepStatus); it is optional and absent on + legacy blob-only executions, so clients must not assume its presence. + """ + class ExecutionRetrieveResponse(BaseModel): data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_child_action_input_param.py b/src/mobilerun_sdk/types/workflows/flow_child_action_input_param.py deleted file mode 100644 index a201a307..00000000 --- a/src/mobilerun_sdk/types/workflows/flow_child_action_input_param.py +++ /dev/null @@ -1,23 +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 Required, Annotated, TypedDict - -from ..._utils import PropertyInfo -from .flow_action_overrides_param import FlowActionOverridesParam - -__all__ = ["FlowChildActionInputParam"] - - -class FlowChildActionInputParam(TypedDict, total=False): - action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] - - position: Required[int] - - continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] - - name_override: Annotated[str, PropertyInfo(alias="nameOverride")] - - overrides: Optional[FlowActionOverridesParam] diff --git a/src/mobilerun_sdk/types/workflows/flow_clone_response.py b/src/mobilerun_sdk/types/workflows/flow_clone_response.py index 57a86370..0688cdc4 100644 --- a/src/mobilerun_sdk/types/workflows/flow_clone_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_clone_response.py @@ -1,10 +1,77 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..flow import Flow +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["FlowCloneResponse"] +__all__ = ["FlowCloneResponse", "Data"] + + +class Data(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowCloneResponse(BaseModel): - data: Flow + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_create_params.py b/src/mobilerun_sdk/types/workflows/flow_create_params.py index b186bad6..002ee9d7 100644 --- a/src/mobilerun_sdk/types/workflows/flow_create_params.py +++ b/src/mobilerun_sdk/types/workflows/flow_create_params.py @@ -2,15 +2,13 @@ from __future__ import annotations -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal, Required, Annotated, TypedDict from ..._types import SequenceNotStr from ..._utils import PropertyInfo -from .flow_action_overrides_param import FlowActionOverridesParam -from .flow_child_action_input_param import FlowChildActionInputParam -__all__ = ["FlowCreateParams", "Action"] +__all__ = ["FlowCreateParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides"] class FlowCreateParams(TypedDict, total=False): @@ -43,15 +41,35 @@ class FlowCreateParams(TypedDict, total=False): self_healing_max_attempts: Annotated[int, PropertyInfo(alias="selfHealingMaxAttempts")] +class ActionChildOverrides(TypedDict, total=False): + params: Dict[str, object] + + +class ActionChild(TypedDict, total=False): + action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] + + position: Required[int] + + continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] + + name_override: Annotated[str, PropertyInfo(alias="nameOverride")] + + overrides: Optional[ActionChildOverrides] + + +class ActionOverrides(TypedDict, total=False): + params: Dict[str, object] + + class Action(TypedDict, total=False): action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] position: Required[int] - children: Iterable[FlowChildActionInputParam] + children: Iterable[ActionChild] continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] name_override: Annotated[str, PropertyInfo(alias="nameOverride")] - overrides: Optional[FlowActionOverridesParam] + overrides: Optional[ActionOverrides] diff --git a/src/mobilerun_sdk/types/workflows/flow_create_response.py b/src/mobilerun_sdk/types/workflows/flow_create_response.py index f9c5feaa..d35319d3 100644 --- a/src/mobilerun_sdk/types/workflows/flow_create_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_create_response.py @@ -1,10 +1,77 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..flow import Flow +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["FlowCreateResponse"] +__all__ = ["FlowCreateResponse", "Data"] + + +class Data(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowCreateResponse(BaseModel): - data: Flow + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_action_overrides_param.py b/src/mobilerun_sdk/types/workflows/flow_dry_run_params.py similarity index 60% rename from src/mobilerun_sdk/types/workflows/flow_action_overrides_param.py rename to src/mobilerun_sdk/types/workflows/flow_dry_run_params.py index 6f74d3f0..23125e12 100644 --- a/src/mobilerun_sdk/types/workflows/flow_action_overrides_param.py +++ b/src/mobilerun_sdk/types/workflows/flow_dry_run_params.py @@ -5,8 +5,8 @@ from typing import Dict from typing_extensions import TypedDict -__all__ = ["FlowActionOverridesParam"] +__all__ = ["FlowDryRunParams"] -class FlowActionOverridesParam(TypedDict, total=False): - params: Dict[str, object] +class FlowDryRunParams(TypedDict, total=False): + payload: Dict[str, object] diff --git a/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py new file mode 100644 index 00000000..d9a5bf30 --- /dev/null +++ b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py @@ -0,0 +1,74 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["FlowDryRunResponse", "Data", "DataAction", "DataGates", "DataValidation", "DataValidationError"] + + +class DataAction(BaseModel): + continue_on_error: bool = FieldInfo(alias="continueOnError") + + method: str + + name: str + + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] + + children: Optional[List[object]] = None + """ + Nested child actions (loop/branch bodies), each the same shape as a + ResolvedAction. + """ + + params: Optional[Dict[str, object]] = None + + +class DataGates(BaseModel): + blocked: bool + + cooldown_active: Optional[bool] = FieldInfo(alias="cooldownActive", default=None) + + device_attached: bool = FieldInfo(alias="deviceAttached") + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + +class DataValidationError(BaseModel): + field: str + + message: str + + +class DataValidation(BaseModel): + valid: bool + + errors: Optional[List[DataValidationError]] = None + + +class Data(BaseModel): + actions: List[DataAction] + + activation: Literal["event", "schedule", "custom"] + + conditions_passed: Optional[bool] = FieldInfo(alias="conditionsPassed", default=None) + + gates: DataGates + + next_fire_time: Optional[str] = FieldInfo(alias="nextFireTime", default=None) + + rate_limited: bool = FieldInfo(alias="rateLimited") + + validation: DataValidation + + would_fire: bool = FieldInfo(alias="wouldFire") + + +class FlowDryRunResponse(BaseModel): + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_list_repairs_response.py b/src/mobilerun_sdk/types/workflows/flow_list_repairs_response.py new file mode 100644 index 00000000..df02dcc0 --- /dev/null +++ b/src/mobilerun_sdk/types/workflows/flow_list_repairs_response.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["FlowListRepairsResponse", "Data", "DataVerdict"] + + +class DataVerdict(BaseModel): + outcome: Literal["ok", "flaky", "broken"] + + summary: str + + reason: Optional[str] = None + + +class Data(BaseModel): + id: str + + agent_run_id: Optional[str] = FieldInfo(alias="agentRunId", default=None) + + attempt: int + + candidate_slug: str = FieldInfo(alias="candidateSlug") + + chat_session_id: Optional[str] = FieldInfo(alias="chatSessionId", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + + episode: int + + error: Optional[str] = None + + failed_step_index: int = FieldInfo(alias="failedStepIndex") + + finished_at: Optional[str] = FieldInfo(alias="finishedAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + max_attempts: int = FieldInfo(alias="maxAttempts") + + original_slug: str = FieldInfo(alias="originalSlug") + + source_execution_id: str = FieldInfo(alias="sourceExecutionId") + + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) + + status: Literal["pending", "running", "canary", "promoting", "repaired", "failed", "escalated"] + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + verdict: Optional[DataVerdict] = None + + +class FlowListRepairsResponse(BaseModel): + data: List[Data] diff --git a/src/mobilerun_sdk/types/workflows/flow_list_response.py b/src/mobilerun_sdk/types/workflows/flow_list_response.py index ff0feb88..36819ffe 100644 --- a/src/mobilerun_sdk/types/workflows/flow_list_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_list_response.py @@ -1,15 +1,80 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo -from ..flow import Flow from ..._models import BaseModel from ..shared.pagination import Pagination -__all__ = ["FlowListResponse"] +__all__ = ["FlowListResponse", "Item"] + + +class Item(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowListResponse(BaseModel): - items: List[Flow] + items: List[Item] pagination: Pagination diff --git a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py index 0a002a69..3c017332 100644 --- a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py @@ -1,10 +1,77 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..flow import Flow +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["FlowRetrieveResponse"] +__all__ = ["FlowRetrieveResponse", "Data"] + + +class Data(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowRetrieveResponse(BaseModel): - data: Flow + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py index 3771e29a..f36de0cd 100644 --- a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py @@ -1,10 +1,77 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..flow import Flow +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["FlowUnblockResponse"] +__all__ = ["FlowUnblockResponse", "Data"] + + +class Data(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowUnblockResponse(BaseModel): - data: Flow + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flow_update_response.py b/src/mobilerun_sdk/types/workflows/flow_update_response.py index 8725080a..b33c1b3e 100644 --- a/src/mobilerun_sdk/types/workflows/flow_update_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_update_response.py @@ -1,10 +1,77 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from ..flow import Flow +from typing import List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + from ..._models import BaseModel -__all__ = ["FlowUpdateResponse"] +__all__ = ["FlowUpdateResponse", "Data"] + + +class Data(BaseModel): + id: str + + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) + + consecutive_failures: int = FieldInfo(alias="consecutiveFailures") + + cooldown_scope: Literal["flow", "device"] = FieldInfo(alias="cooldownScope") + + cooldown_seconds: Optional[int] = FieldInfo(alias="cooldownSeconds", default=None) + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + + description: Optional[str] = None + + device_ids: List[str] = FieldInfo(alias="deviceIds") + + enabled: bool + + health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") + + last_failure_at: Optional[str] = FieldInfo(alias="lastFailureAt", default=None) + + last_failure_code: Optional[ + Literal["device_not_found", "permission_denied", "client_error", "transient", "logic", "invalid_config"] + ] = FieldInfo(alias="lastFailureCode", default=None) + + last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + + name: str + + notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") + + notify_on_success: bool = FieldInfo(alias="notifyOnSuccess") + + notify_webhook_id: Optional[str] = FieldInfo(alias="notifyWebhookId", default=None) + + owner_id: str = FieldInfo(alias="ownerId") + + self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") + + self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts") + + status: Literal["healthy", "failing", "blocked"] + + template_resolution_version: int = FieldInfo(alias="templateResolutionVersion") + """Template-resolver semantics this flow runs under (MVA-23). + + 1 = legacy (missing/forbidden/null all resolve to ''). 2 = typed + (missing/forbidden throw, a whole-token null stays JSON null). Existing flows + stay 1; new flows default to 2. + """ + + trigger_id: str = FieldInfo(alias="triggerId") + + updated_at: Optional[str] = FieldInfo(alias="updatedAt", default=None) + + user_id: str = FieldInfo(alias="userId") + """Deprecated: use ownerId (tenancy) / createdBy (actor).""" class FlowUpdateResponse(BaseModel): - data: Flow + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flows/__init__.py b/src/mobilerun_sdk/types/workflows/flows/__init__.py index fa77a335..54847343 100644 --- a/src/mobilerun_sdk/types/workflows/flows/__init__.py +++ b/src/mobilerun_sdk/types/workflows/flows/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations -from .flow_action import FlowAction as FlowAction from .action_add_params import ActionAddParams as ActionAddParams from .action_add_response import ActionAddResponse as ActionAddResponse from .action_list_response import ActionListResponse as ActionListResponse diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py index 749fab6b..1275209c 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py @@ -2,14 +2,12 @@ from __future__ import annotations -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Required, Annotated, TypedDict from ...._utils import PropertyInfo -from ..flow_action_overrides_param import FlowActionOverridesParam -from ..flow_child_action_input_param import FlowChildActionInputParam -__all__ = ["ActionAddParams"] +__all__ = ["ActionAddParams", "Child", "ChildOverrides", "Overrides"] class ActionAddParams(TypedDict, total=False): @@ -17,12 +15,32 @@ class ActionAddParams(TypedDict, total=False): position: Required[int] - children: Iterable[FlowChildActionInputParam] + children: Iterable[Child] continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] name_override: Annotated[str, PropertyInfo(alias="nameOverride")] - overrides: Optional[FlowActionOverridesParam] + overrides: Optional[Overrides] parent_flow_action_id: Annotated[Optional[str], PropertyInfo(alias="parentFlowActionId")] + + +class ChildOverrides(TypedDict, total=False): + params: Dict[str, object] + + +class Child(TypedDict, total=False): + action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] + + position: Required[int] + + continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] + + name_override: Annotated[str, PropertyInfo(alias="nameOverride")] + + overrides: Optional[ChildOverrides] + + +class Overrides(TypedDict, total=False): + params: Dict[str, object] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py index 03d4e313..00d02c81 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py @@ -1,10 +1,37 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Dict, Optional + +from pydantic import Field as FieldInfo + from ...._models import BaseModel -from .flow_action import FlowAction -__all__ = ["ActionAddResponse"] +__all__ = ["ActionAddResponse", "Data", "DataOverrides"] + + +class DataOverrides(BaseModel): + params: Optional[Dict[str, object]] = None + + +class Data(BaseModel): + id: str + + action_id: str = FieldInfo(alias="actionId") + + continue_on_error: bool = FieldInfo(alias="continueOnError") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + name_override: Optional[str] = FieldInfo(alias="nameOverride", default=None) + + overrides: Optional[DataOverrides] = None + + parent_flow_action_id: Optional[str] = FieldInfo(alias="parentFlowActionId", default=None) + + position: int class ActionAddResponse(BaseModel): - data: FlowAction + data: Data diff --git a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py index 7f6bd53b..88c4965b 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py @@ -1,12 +1,37 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import Dict, List, Optional + +from pydantic import Field as FieldInfo from ...._models import BaseModel -from .flow_action import FlowAction -__all__ = ["ActionListResponse"] +__all__ = ["ActionListResponse", "Data", "DataOverrides"] + + +class DataOverrides(BaseModel): + params: Optional[Dict[str, object]] = None + + +class Data(BaseModel): + id: str + + action_id: str = FieldInfo(alias="actionId") + + continue_on_error: bool = FieldInfo(alias="continueOnError") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + name_override: Optional[str] = FieldInfo(alias="nameOverride", default=None) + + overrides: Optional[DataOverrides] = None + + parent_flow_action_id: Optional[str] = FieldInfo(alias="parentFlowActionId", default=None) + + position: int class ActionListResponse(BaseModel): - data: List[FlowAction] + data: List[Data] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py index 359f2287..ec5c42a1 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py @@ -2,29 +2,47 @@ from __future__ import annotations -from typing import Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Required, Annotated, TypedDict from ...._utils import PropertyInfo -from ..flow_action_overrides_param import FlowActionOverridesParam -from ..flow_child_action_input_param import FlowChildActionInputParam -__all__ = ["ActionReplaceParams", "Action"] +__all__ = ["ActionReplaceParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides"] class ActionReplaceParams(TypedDict, total=False): actions: Required[Iterable[Action]] +class ActionChildOverrides(TypedDict, total=False): + params: Dict[str, object] + + +class ActionChild(TypedDict, total=False): + action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] + + position: Required[int] + + continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] + + name_override: Annotated[str, PropertyInfo(alias="nameOverride")] + + overrides: Optional[ActionChildOverrides] + + +class ActionOverrides(TypedDict, total=False): + params: Dict[str, object] + + class Action(TypedDict, total=False): action_id: Required[Annotated[str, PropertyInfo(alias="actionId")]] position: Required[int] - children: Iterable[FlowChildActionInputParam] + children: Iterable[ActionChild] continue_on_error: Annotated[bool, PropertyInfo(alias="continueOnError")] name_override: Annotated[str, PropertyInfo(alias="nameOverride")] - overrides: Optional[FlowActionOverridesParam] + overrides: Optional[ActionOverrides] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py index 2914bfaf..cf358f90 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py @@ -1,12 +1,37 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import Dict, List, Optional + +from pydantic import Field as FieldInfo from ...._models import BaseModel -from .flow_action import FlowAction -__all__ = ["ActionReplaceResponse"] +__all__ = ["ActionReplaceResponse", "Data", "DataOverrides"] + + +class DataOverrides(BaseModel): + params: Optional[Dict[str, object]] = None + + +class Data(BaseModel): + id: str + + action_id: str = FieldInfo(alias="actionId") + + continue_on_error: bool = FieldInfo(alias="continueOnError") + + created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) + + flow_id: str = FieldInfo(alias="flowId") + + name_override: Optional[str] = FieldInfo(alias="nameOverride", default=None) + + overrides: Optional[DataOverrides] = None + + parent_flow_action_id: Optional[str] = FieldInfo(alias="parentFlowActionId", default=None) + + position: int class ActionReplaceResponse(BaseModel): - data: List[FlowAction] + data: List[Data] diff --git a/src/mobilerun_sdk/types/workflows/flows/flow_action.py b/src/mobilerun_sdk/types/workflows/flows/flow_action.py deleted file mode 100644 index e2731702..00000000 --- a/src/mobilerun_sdk/types/workflows/flows/flow_action.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional - -from pydantic import Field as FieldInfo - -from ...._models import BaseModel - -__all__ = ["FlowAction", "Overrides"] - - -class Overrides(BaseModel): - params: Optional[Dict[str, object]] = None - - -class FlowAction(BaseModel): - id: str - - action_id: str = FieldInfo(alias="actionId") - - continue_on_error: bool = FieldInfo(alias="continueOnError") - - created_at: Optional[str] = FieldInfo(alias="createdAt", default=None) - - flow_id: str = FieldInfo(alias="flowId") - - name_override: Optional[str] = FieldInfo(alias="nameOverride", default=None) - - overrides: Optional[Overrides] = None - - parent_flow_action_id: Optional[str] = FieldInfo(alias="parentFlowActionId", default=None) - - position: int diff --git a/src/mobilerun_sdk/types/workflows/trigger_update_params.py b/src/mobilerun_sdk/types/workflows/trigger_update_params.py index 7ecd2f32..aadb59f6 100644 --- a/src/mobilerun_sdk/types/workflows/trigger_update_params.py +++ b/src/mobilerun_sdk/types/workflows/trigger_update_params.py @@ -13,9 +13,10 @@ class TriggerUpdateParams(TypedDict, total=False): activation: Literal["event", "schedule", "custom"] - conditions: Conditions + conditions: Optional[Conditions] - custom_payload_schema: Annotated[Dict[str, object], PropertyInfo(alias="customPayloadSchema")] + custom_payload_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="customPayloadSchema")] + """Optional JSON Schema for validating payloads sent to this custom trigger""" description: str @@ -23,7 +24,7 @@ class TriggerUpdateParams(TypedDict, total=False): name: str - schedule_rule: Annotated[ScheduleRule, PropertyInfo(alias="scheduleRule")] + schedule_rule: Annotated[Optional[ScheduleRule], PropertyInfo(alias="scheduleRule")] timezone: Optional[str] diff --git a/src/mobilerun_sdk/types/workflows/events/__init__.py b/tests/api_resources/app_events/__init__.py similarity index 70% rename from src/mobilerun_sdk/types/workflows/events/__init__.py rename to tests/api_resources/app_events/__init__.py index f8ee8b14..fd8019a9 100644 --- a/src/mobilerun_sdk/types/workflows/events/__init__.py +++ b/tests/api_resources/app_events/__init__.py @@ -1,3 +1 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations diff --git a/tests/api_resources/app_events/test_catalog.py b/tests/api_resources/app_events/test_catalog.py new file mode 100644 index 00000000..ff91f737 --- /dev/null +++ b/tests/api_resources/app_events/test_catalog.py @@ -0,0 +1,164 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.app_events import CatalogListResponse, CatalogRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestCatalog: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Mobilerun) -> None: + catalog = client.app_events.catalog.retrieve( + "x", + ) + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Mobilerun) -> None: + response = client.app_events.catalog.with_raw_response.retrieve( + "x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + catalog = response.parse() + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Mobilerun) -> None: + with client.app_events.catalog.with_streaming_response.retrieve( + "x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + catalog = response.parse() + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `app_event_type` but received ''"): + client.app_events.catalog.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + catalog = client.app_events.catalog.list() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.app_events.catalog.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + catalog = response.parse() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.app_events.catalog.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + catalog = response.parse() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncCatalog: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: + catalog = await async_client.app_events.catalog.retrieve( + "x", + ) + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: + response = await async_client.app_events.catalog.with_raw_response.retrieve( + "x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + catalog = await response.parse() + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: + async with async_client.app_events.catalog.with_streaming_response.retrieve( + "x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + catalog = await response.parse() + assert_matches_type(CatalogRetrieveResponse, catalog, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `app_event_type` but received ''"): + await async_client.app_events.catalog.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + catalog = await async_client.app_events.catalog.list() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.app_events.catalog.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + catalog = await response.parse() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.app_events.catalog.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + catalog = await response.parse() + assert_matches_type(CatalogListResponse, catalog, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/credentials/test_packages.py b/tests/api_resources/credentials/test_packages.py index 9e0b50d0..8e9b173d 100644 --- a/tests/api_resources/credentials/test_packages.py +++ b/tests/api_resources/credentials/test_packages.py @@ -9,7 +9,11 @@ from tests.utils import assert_matches_type from mobilerun_sdk import Mobilerun, AsyncMobilerun -from mobilerun_sdk.types.credentials import PackageListResponse, PackageCreateResponse +from mobilerun_sdk.types.credentials import ( + PackageListResponse, + PackageCreateResponse, + PackageListAllResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -93,6 +97,34 @@ def test_path_params_list(self, client: Mobilerun) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_all(self, client: Mobilerun) -> None: + package = client.credentials.packages.list_all() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list_all(self, client: Mobilerun) -> None: + response = client.credentials.packages.with_raw_response.list_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + package = response.parse() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list_all(self, client: Mobilerun) -> None: + with client.credentials.packages.with_streaming_response.list_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + package = response.parse() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncPackages: parametrize = pytest.mark.parametrize( @@ -174,3 +206,31 @@ async def test_path_params_list(self, async_client: AsyncMobilerun) -> None: await async_client.credentials.packages.with_raw_response.list( "", ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_all(self, async_client: AsyncMobilerun) -> None: + package = await async_client.credentials.packages.list_all() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list_all(self, async_client: AsyncMobilerun) -> None: + response = await async_client.credentials.packages.with_raw_response.list_all() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + package = await response.parse() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list_all(self, async_client: AsyncMobilerun) -> None: + async with async_client.credentials.packages.with_streaming_response.list_all() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + package = await response.parse() + assert_matches_type(PackageListAllResponse, package, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/devices/esim/__init__.py b/tests/api_resources/devices/esim/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/devices/esim/__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/esim/test_apn.py b/tests/api_resources/devices/esim/test_apn.py new file mode 100644 index 00000000..514dcdde --- /dev/null +++ b/tests/api_resources/devices/esim/test_apn.py @@ -0,0 +1,430 @@ +# 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 tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.devices.esim import ApnListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestApn: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.list( + device_id="deviceId", + ) + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.list( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.devices.esim.apn.with_raw_response.list( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = response.parse() + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.devices.esim.apn.with_streaming_response.list( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = response.parse() + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.esim.apn.with_raw_response.list( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_select(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_select_with_all_params(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + x_device_display_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_select(self, client: Mobilerun) -> None: + response = client.devices.esim.apn.with_raw_response.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = response.parse() + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_select(self, client: Mobilerun) -> None: + with client.devices.esim.apn.with_streaming_response.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = response.parse() + assert apn is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_select(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.esim.apn.with_raw_response.select( + device_id="", + apn_id=0, + sub_id=0, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_set(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_set_with_all_params(self, client: Mobilerun) -> None: + apn = client.devices.esim.apn.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + x_device_display_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_set(self, client: Mobilerun) -> None: + response = client.devices.esim.apn.with_raw_response.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = response.parse() + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_set(self, client: Mobilerun) -> None: + with client.devices.esim.apn.with_streaming_response.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = response.parse() + assert apn is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_set(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.esim.apn.with_raw_response.set( + device_id="", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) + + +class TestAsyncApn: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.list( + device_id="deviceId", + ) + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.list( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.esim.apn.with_raw_response.list( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = await response.parse() + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.esim.apn.with_streaming_response.list( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = await response.parse() + assert_matches_type(Optional[ApnListResponse], apn, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.esim.apn.with_raw_response.list( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_select(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_select_with_all_params(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + x_device_display_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_select(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.esim.apn.with_raw_response.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = await response.parse() + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_select(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.esim.apn.with_streaming_response.select( + device_id="deviceId", + apn_id=0, + sub_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = await response.parse() + assert apn is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_select(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.esim.apn.with_raw_response.select( + device_id="", + apn_id=0, + sub_id=0, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_set(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_set_with_all_params(self, async_client: AsyncMobilerun) -> None: + apn = await async_client.devices.esim.apn.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + x_device_display_id=0, + ) + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_set(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.esim.apn.with_raw_response.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + apn = await response.parse() + assert apn is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_set(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.esim.apn.with_streaming_response.set( + device_id="deviceId", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + apn = await response.parse() + assert apn is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_set(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.esim.apn.with_raw_response.set( + device_id="", + apn="apn", + mcc="mcc", + mnc="mnc", + name="name", + protocol="protocol", + roaming_protocol="roamingProtocol", + sub_id=0, + type="type", + ) diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py index 8688921e..c1281d68 100644 --- a/tests/api_resources/devices/test_apps.py +++ b/tests/api_resources/devices/test_apps.py @@ -11,6 +11,7 @@ from mobilerun_sdk import Mobilerun, AsyncMobilerun from mobilerun_sdk.types.devices import ( AppListResponse, + AppListInstallsResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -134,6 +135,74 @@ def test_path_params_delete(self, client: Mobilerun) -> None: device_id="deviceId", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_grant_permission(self, client: Mobilerun) -> None: + app = client.devices.apps.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_grant_permission_with_all_params(self, client: Mobilerun) -> None: + app = client.devices.apps.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + x_device_display_id=0, + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_grant_permission(self, client: Mobilerun) -> None: + response = client.devices.apps.with_raw_response.grant_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + def test_streaming_response_grant_permission(self, client: Mobilerun) -> None: + with client.devices.apps.with_streaming_response.grant_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + def test_path_params_grant_permission(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.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="", + package_name="packageName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"): + client.devices.apps.with_raw_response.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_install_overload_1(self, client: Mobilerun) -> None: @@ -250,6 +319,125 @@ def test_path_params_install_overload_2(self, client: Mobilerun) -> None: package_name="x", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_installs(self, client: Mobilerun) -> None: + app = client.devices.apps.list_installs( + device_id="deviceId", + ) + assert_matches_type(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_installs_with_all_params(self, client: Mobilerun) -> None: + app = client.devices.apps.list_installs( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list_installs(self, client: Mobilerun) -> None: + response = client.devices.apps.with_raw_response.list_installs( + 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(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list_installs(self, client: Mobilerun) -> None: + with client.devices.apps.with_streaming_response.list_installs( + 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(AppListInstallsResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list_installs(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_installs( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_revoke_permission(self, client: Mobilerun) -> None: + app = client.devices.apps.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_revoke_permission_with_all_params(self, client: Mobilerun) -> None: + app = client.devices.apps.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + x_device_display_id=0, + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_revoke_permission(self, client: Mobilerun) -> None: + response = client.devices.apps.with_raw_response.revoke_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + def test_streaming_response_revoke_permission(self, client: Mobilerun) -> None: + with client.devices.apps.with_streaming_response.revoke_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + def test_path_params_revoke_permission(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.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="", + package_name="packageName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"): + client.devices.apps.with_raw_response.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_start(self, client: Mobilerun) -> None: @@ -497,6 +685,74 @@ async def test_path_params_delete(self, async_client: AsyncMobilerun) -> None: device_id="deviceId", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_grant_permission(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_grant_permission_with_all_params(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + x_device_display_id=0, + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_grant_permission(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.apps.with_raw_response.grant_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + async def test_streaming_response_grant_permission(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.apps.with_streaming_response.grant_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + async def test_path_params_grant_permission(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.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="", + package_name="packageName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"): + await async_client.devices.apps.with_raw_response.grant_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_install_overload_1(self, async_client: AsyncMobilerun) -> None: @@ -613,6 +869,125 @@ async def test_path_params_install_overload_2(self, async_client: AsyncMobilerun package_name="x", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_installs(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.list_installs( + device_id="deviceId", + ) + assert_matches_type(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_installs_with_all_params(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.list_installs( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list_installs(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.apps.with_raw_response.list_installs( + 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(AppListInstallsResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list_installs(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.apps.with_streaming_response.list_installs( + 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(AppListInstallsResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list_installs(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_installs( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_revoke_permission(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_revoke_permission_with_all_params(self, async_client: AsyncMobilerun) -> None: + app = await async_client.devices.apps.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="packageName", + x_device_display_id=0, + ) + assert app is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_revoke_permission(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.apps.with_raw_response.revoke_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + async def test_streaming_response_revoke_permission(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.apps.with_streaming_response.revoke_permission( + permission="POST_NOTIFICATIONS", + 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="Mock server tests are disabled") + @parametrize + async def test_path_params_revoke_permission(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.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="", + package_name="packageName", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `package_name` but received ''"): + await async_client.devices.apps.with_raw_response.revoke_permission( + permission="POST_NOTIFICATIONS", + device_id="deviceId", + package_name="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_start(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/api_resources/devices/test_browser.py b/tests/api_resources/devices/test_browser.py new file mode 100644 index 00000000..d4fd1cff --- /dev/null +++ b/tests/api_resources/devices/test_browser.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.devices import BrowserExecuteScriptResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBrowser: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_execute_script(self, client: Mobilerun) -> None: + browser = client.devices.browser.execute_script( + device_id="deviceId", + script="script", + ) + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_execute_script_with_all_params(self, client: Mobilerun) -> None: + browser = client.devices.browser.execute_script( + device_id="deviceId", + script="script", + x_device_display_id=0, + ) + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_execute_script(self, client: Mobilerun) -> None: + response = client.devices.browser.with_raw_response.execute_script( + device_id="deviceId", + script="script", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser = response.parse() + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_execute_script(self, client: Mobilerun) -> None: + with client.devices.browser.with_streaming_response.execute_script( + device_id="deviceId", + script="script", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser = response.parse() + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_execute_script(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.browser.with_raw_response.execute_script( + device_id="", + script="script", + ) + + +class TestAsyncBrowser: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_execute_script(self, async_client: AsyncMobilerun) -> None: + browser = await async_client.devices.browser.execute_script( + device_id="deviceId", + script="script", + ) + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_execute_script_with_all_params(self, async_client: AsyncMobilerun) -> None: + browser = await async_client.devices.browser.execute_script( + device_id="deviceId", + script="script", + x_device_display_id=0, + ) + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_execute_script(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.browser.with_raw_response.execute_script( + device_id="deviceId", + script="script", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + browser = await response.parse() + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_execute_script(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.browser.with_streaming_response.execute_script( + device_id="deviceId", + script="script", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + browser = await response.parse() + assert_matches_type(BrowserExecuteScriptResponse, browser, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_execute_script(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.browser.with_raw_response.execute_script( + device_id="", + script="script", + ) diff --git a/tests/api_resources/devices/test_deep_link.py b/tests/api_resources/devices/test_deep_link.py new file mode 100644 index 00000000..a39804d9 --- /dev/null +++ b/tests/api_resources/devices/test_deep_link.py @@ -0,0 +1,140 @@ +# 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_sdk import Mobilerun, AsyncMobilerun + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestDeepLink: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_execute_deep_link(self, client: Mobilerun) -> None: + deep_link = client.devices.deep_link.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_execute_deep_link_with_all_params(self, client: Mobilerun) -> None: + deep_link = client.devices.deep_link.execute_deep_link( + device_id="deviceId", + deep_link="x", + action="action", + bundle_id="bundleId", + package_name="packageName", + x_device_display_id=0, + ) + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_execute_deep_link(self, client: Mobilerun) -> None: + response = client.devices.deep_link.with_raw_response.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deep_link = response.parse() + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_execute_deep_link(self, client: Mobilerun) -> None: + with client.devices.deep_link.with_streaming_response.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deep_link = response.parse() + assert deep_link is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_execute_deep_link(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.deep_link.with_raw_response.execute_deep_link( + device_id="", + deep_link="x", + ) + + +class TestAsyncDeepLink: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_execute_deep_link(self, async_client: AsyncMobilerun) -> None: + deep_link = await async_client.devices.deep_link.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_execute_deep_link_with_all_params(self, async_client: AsyncMobilerun) -> None: + deep_link = await async_client.devices.deep_link.execute_deep_link( + device_id="deviceId", + deep_link="x", + action="action", + bundle_id="bundleId", + package_name="packageName", + x_device_display_id=0, + ) + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_execute_deep_link(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.deep_link.with_raw_response.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + deep_link = await response.parse() + assert deep_link is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_execute_deep_link(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.deep_link.with_streaming_response.execute_deep_link( + device_id="deviceId", + deep_link="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + deep_link = await response.parse() + assert deep_link is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_execute_deep_link(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.deep_link.with_raw_response.execute_deep_link( + device_id="", + deep_link="x", + ) diff --git a/tests/api_resources/devices/test_esim.py b/tests/api_resources/devices/test_esim.py index 3ff9449d..82541c22 100644 --- a/tests/api_resources/devices/test_esim.py +++ b/tests/api_resources/devices/test_esim.py @@ -11,6 +11,7 @@ from mobilerun_sdk import Mobilerun, AsyncMobilerun from mobilerun_sdk.types.devices import ( EsimListResponse, + EsimStatusResponse, EsimActivateResponse, ) @@ -246,6 +247,113 @@ def test_path_params_remove(self, client: Mobilerun) -> None: sub_id=0, ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_set_roaming(self, client: Mobilerun) -> None: + esim = client.devices.esim.set_roaming( + device_id="deviceId", + enabled=True, + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_set_roaming_with_all_params(self, client: Mobilerun) -> None: + esim = client.devices.esim.set_roaming( + device_id="deviceId", + enabled=True, + x_device_display_id=0, + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_set_roaming(self, client: Mobilerun) -> None: + response = client.devices.esim.with_raw_response.set_roaming( + device_id="deviceId", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_set_roaming(self, client: Mobilerun) -> None: + with client.devices.esim.with_streaming_response.set_roaming( + device_id="deviceId", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert esim is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_set_roaming(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.esim.with_raw_response.set_roaming( + device_id="", + enabled=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_status(self, client: Mobilerun) -> None: + esim = client.devices.esim.status( + device_id="deviceId", + ) + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_status_with_all_params(self, client: Mobilerun) -> None: + esim = client.devices.esim.status( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_status(self, client: Mobilerun) -> None: + response = client.devices.esim.with_raw_response.status( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_status(self, client: Mobilerun) -> None: + with client.devices.esim.with_streaming_response.status( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_status(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.esim.with_raw_response.status( + device_id="", + ) + class TestAsyncEsim: parametrize = pytest.mark.parametrize( @@ -477,3 +585,110 @@ async def test_path_params_remove(self, async_client: AsyncMobilerun) -> None: device_id="", sub_id=0, ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_set_roaming(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.devices.esim.set_roaming( + device_id="deviceId", + enabled=True, + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_set_roaming_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.devices.esim.set_roaming( + device_id="deviceId", + enabled=True, + x_device_display_id=0, + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_set_roaming(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.esim.with_raw_response.set_roaming( + device_id="deviceId", + enabled=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_set_roaming(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.esim.with_streaming_response.set_roaming( + device_id="deviceId", + enabled=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert esim is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_set_roaming(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.esim.with_raw_response.set_roaming( + device_id="", + enabled=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_status(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.devices.esim.status( + device_id="deviceId", + ) + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_status_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.devices.esim.status( + device_id="deviceId", + x_device_display_id=0, + ) + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_status(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.esim.with_raw_response.status( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_status(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.esim.with_streaming_response.status( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(Optional[EsimStatusResponse], esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_status(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.esim.with_raw_response.status( + device_id="", + ) diff --git a/tests/api_resources/devices/test_kiosk.py b/tests/api_resources/devices/test_kiosk.py new file mode 100644 index 00000000..ac702eed --- /dev/null +++ b/tests/api_resources/devices/test_kiosk.py @@ -0,0 +1,236 @@ +# 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_sdk import Mobilerun, AsyncMobilerun + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestKiosk: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_disable(self, client: Mobilerun) -> None: + kiosk = client.devices.kiosk.disable( + device_id="deviceId", + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_disable_with_all_params(self, client: Mobilerun) -> None: + kiosk = client.devices.kiosk.disable( + device_id="deviceId", + x_device_display_id=0, + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_disable(self, client: Mobilerun) -> None: + response = client.devices.kiosk.with_raw_response.disable( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kiosk = response.parse() + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_disable(self, client: Mobilerun) -> None: + with client.devices.kiosk.with_streaming_response.disable( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kiosk = response.parse() + assert kiosk is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_disable(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.kiosk.with_raw_response.disable( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_enable(self, client: Mobilerun) -> None: + kiosk = client.devices.kiosk.enable( + device_id="deviceId", + package_name="x", + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_enable_with_all_params(self, client: Mobilerun) -> None: + kiosk = client.devices.kiosk.enable( + device_id="deviceId", + package_name="x", + x_device_display_id=0, + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_enable(self, client: Mobilerun) -> None: + response = client.devices.kiosk.with_raw_response.enable( + device_id="deviceId", + package_name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kiosk = response.parse() + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_enable(self, client: Mobilerun) -> None: + with client.devices.kiosk.with_streaming_response.enable( + device_id="deviceId", + package_name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kiosk = response.parse() + assert kiosk is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_enable(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.kiosk.with_raw_response.enable( + device_id="", + package_name="x", + ) + + +class TestAsyncKiosk: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_disable(self, async_client: AsyncMobilerun) -> None: + kiosk = await async_client.devices.kiosk.disable( + device_id="deviceId", + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_disable_with_all_params(self, async_client: AsyncMobilerun) -> None: + kiosk = await async_client.devices.kiosk.disable( + device_id="deviceId", + x_device_display_id=0, + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_disable(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.kiosk.with_raw_response.disable( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kiosk = await response.parse() + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_disable(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.kiosk.with_streaming_response.disable( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kiosk = await response.parse() + assert kiosk is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_disable(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.kiosk.with_raw_response.disable( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_enable(self, async_client: AsyncMobilerun) -> None: + kiosk = await async_client.devices.kiosk.enable( + device_id="deviceId", + package_name="x", + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_enable_with_all_params(self, async_client: AsyncMobilerun) -> None: + kiosk = await async_client.devices.kiosk.enable( + device_id="deviceId", + package_name="x", + x_device_display_id=0, + ) + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_enable(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.kiosk.with_raw_response.enable( + device_id="deviceId", + package_name="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + kiosk = await response.parse() + assert kiosk is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_enable(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.kiosk.with_streaming_response.enable( + device_id="deviceId", + package_name="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + kiosk = await response.parse() + assert kiosk is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_enable(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.kiosk.with_raw_response.enable( + device_id="", + package_name="x", + ) diff --git a/tests/api_resources/devices/test_location.py b/tests/api_resources/devices/test_location.py index 2ec5cb0d..8d156acd 100644 --- a/tests/api_resources/devices/test_location.py +++ b/tests/api_resources/devices/test_location.py @@ -68,6 +68,57 @@ def test_path_params_get(self, client: Mobilerun) -> None: device_id="", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_reset(self, client: Mobilerun) -> None: + location = client.devices.location.reset( + device_id="deviceId", + ) + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_reset_with_all_params(self, client: Mobilerun) -> None: + location = client.devices.location.reset( + device_id="deviceId", + x_device_display_id=0, + ) + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_reset(self, client: Mobilerun) -> None: + response = client.devices.location.with_raw_response.reset( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = response.parse() + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_reset(self, client: Mobilerun) -> None: + with client.devices.location.with_streaming_response.reset( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = response.parse() + assert location is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_reset(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.location.with_raw_response.reset( + device_id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_set(self, client: Mobilerun) -> None: @@ -186,6 +237,57 @@ async def test_path_params_get(self, async_client: AsyncMobilerun) -> None: device_id="", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_reset(self, async_client: AsyncMobilerun) -> None: + location = await async_client.devices.location.reset( + device_id="deviceId", + ) + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_reset_with_all_params(self, async_client: AsyncMobilerun) -> None: + location = await async_client.devices.location.reset( + device_id="deviceId", + x_device_display_id=0, + ) + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_reset(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.location.with_raw_response.reset( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + location = await response.parse() + assert location is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_reset(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.location.with_streaming_response.reset( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + location = await response.parse() + assert location is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_reset(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.location.with_raw_response.reset( + device_id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_set(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/api_resources/devices/test_media_sessions.py b/tests/api_resources/devices/test_media_sessions.py new file mode 100644 index 00000000..382f26e5 --- /dev/null +++ b/tests/api_resources/devices/test_media_sessions.py @@ -0,0 +1,440 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.devices import ( + MediaSessionCreateResponse, + MediaSessionActivateResponse, + MediaSessionRetrieveCurrentResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMediaSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Mobilerun) -> None: + media_session = client.devices.media_sessions.create( + device_id="deviceId", + camera=True, + microphone=True, + ) + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Mobilerun) -> None: + response = client.devices.media_sessions.with_raw_response.create( + device_id="deviceId", + camera=True, + microphone=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = response.parse() + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Mobilerun) -> None: + with client.devices.media_sessions.with_streaming_response.create( + device_id="deviceId", + camera=True, + microphone=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = response.parse() + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.media_sessions.with_raw_response.create( + device_id="", + camera=True, + microphone=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Mobilerun) -> None: + media_session = client.devices.media_sessions.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + assert media_session is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Mobilerun) -> None: + response = client.devices.media_sessions.with_raw_response.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = response.parse() + assert media_session is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Mobilerun) -> None: + with client.devices.media_sessions.with_streaming_response.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = response.parse() + assert media_session is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.media_sessions.with_raw_response.delete( + session_id="sessionId", + device_id="", + x_media_control_token="X-Media-Control-Token", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.devices.media_sessions.with_raw_response.delete( + session_id="", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_activate(self, client: Mobilerun) -> None: + media_session = client.devices.media_sessions.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_activate(self, client: Mobilerun) -> None: + response = client.devices.media_sessions.with_raw_response.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = response.parse() + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_activate(self, client: Mobilerun) -> None: + with client.devices.media_sessions.with_streaming_response.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = response.parse() + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_activate(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.media_sessions.with_raw_response.activate( + session_id="sessionId", + device_id="", + x_media_control_token="X-Media-Control-Token", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + client.devices.media_sessions.with_raw_response.activate( + session_id="", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_current(self, client: Mobilerun) -> None: + media_session = client.devices.media_sessions.retrieve_current( + "deviceId", + ) + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_current(self, client: Mobilerun) -> None: + response = client.devices.media_sessions.with_raw_response.retrieve_current( + "deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = response.parse() + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_current(self, client: Mobilerun) -> None: + with client.devices.media_sessions.with_streaming_response.retrieve_current( + "deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = response.parse() + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve_current(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.media_sessions.with_raw_response.retrieve_current( + "", + ) + + +class TestAsyncMediaSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncMobilerun) -> None: + media_session = await async_client.devices.media_sessions.create( + device_id="deviceId", + camera=True, + microphone=True, + ) + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.media_sessions.with_raw_response.create( + device_id="deviceId", + camera=True, + microphone=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = await response.parse() + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.media_sessions.with_streaming_response.create( + device_id="deviceId", + camera=True, + microphone=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = await response.parse() + assert_matches_type(MediaSessionCreateResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(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.media_sessions.with_raw_response.create( + device_id="", + camera=True, + microphone=True, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncMobilerun) -> None: + media_session = await async_client.devices.media_sessions.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + assert media_session is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.media_sessions.with_raw_response.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = await response.parse() + assert media_session is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.media_sessions.with_streaming_response.delete( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = await response.parse() + assert media_session is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.media_sessions.with_raw_response.delete( + session_id="sessionId", + device_id="", + x_media_control_token="X-Media-Control-Token", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.devices.media_sessions.with_raw_response.delete( + session_id="", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_activate(self, async_client: AsyncMobilerun) -> None: + media_session = await async_client.devices.media_sessions.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_activate(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.media_sessions.with_raw_response.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = await response.parse() + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_activate(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.media_sessions.with_streaming_response.activate( + session_id="sessionId", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = await response.parse() + assert_matches_type(MediaSessionActivateResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_activate(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.media_sessions.with_raw_response.activate( + session_id="sessionId", + device_id="", + x_media_control_token="X-Media-Control-Token", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): + await async_client.devices.media_sessions.with_raw_response.activate( + session_id="", + device_id="deviceId", + x_media_control_token="X-Media-Control-Token", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_current(self, async_client: AsyncMobilerun) -> None: + media_session = await async_client.devices.media_sessions.retrieve_current( + "deviceId", + ) + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_current(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.media_sessions.with_raw_response.retrieve_current( + "deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + media_session = await response.parse() + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_current(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.media_sessions.with_streaming_response.retrieve_current( + "deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + media_session = await response.parse() + assert_matches_type(MediaSessionRetrieveCurrentResponse, media_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve_current(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.media_sessions.with_raw_response.retrieve_current( + "", + ) diff --git a/tests/api_resources/devices/test_recordings.py b/tests/api_resources/devices/test_recordings.py new file mode 100644 index 00000000..f3e134fb --- /dev/null +++ b/tests/api_resources/devices/test_recordings.py @@ -0,0 +1,759 @@ +# 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 tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.devices import ( + RecordingListResponse, + RecordingStopResponse, + RecordingStartResponse, + RecordingStatusResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestRecordings: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + recording = client.devices.recordings.list( + device_id="deviceId", + ) + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + recording = client.devices.recordings.list( + device_id="deviceId", + status="status", + type="type", + ) + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.list( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.list( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.list( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Mobilerun) -> None: + recording = client.devices.recordings.delete( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.delete( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.delete( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.delete( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + client.devices.recordings.with_raw_response.delete( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_start(self, client: Mobilerun) -> None: + recording = client.devices.recordings.start( + device_id="deviceId", + ) + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_start_with_all_params(self, client: Mobilerun) -> None: + recording = client.devices.recordings.start( + device_id="deviceId", + name="name", + retention_days=1, + types=["string"], + ) + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_start(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.start( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_start(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.start( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.start( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_status(self, client: Mobilerun) -> None: + recording = client.devices.recordings.status( + recording_id="recordingId", + device_id="deviceId", + ) + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_status(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.status( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_status(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.status( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_status(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.recordings.with_raw_response.status( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + client.devices.recordings.with_raw_response.status( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_stop(self, client: Mobilerun) -> None: + recording = client.devices.recordings.stop( + recording_id="recordingId", + device_id="deviceId", + ) + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_stop(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.stop( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_stop(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.stop( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_stop(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.recordings.with_raw_response.stop( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + client.devices.recordings.with_raw_response.stop( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_trajectory(self, client: Mobilerun) -> None: + recording = client.devices.recordings.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_trajectory(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_trajectory(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_trajectory(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.recordings.with_raw_response.trajectory( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + client.devices.recordings.with_raw_response.trajectory( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_video(self, client: Mobilerun) -> None: + recording = client.devices.recordings.video( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_video(self, client: Mobilerun) -> None: + response = client.devices.recordings.with_raw_response.video( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_video(self, client: Mobilerun) -> None: + with client.devices.recordings.with_streaming_response.video( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_video(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"): + client.devices.recordings.with_raw_response.video( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + client.devices.recordings.with_raw_response.video( + recording_id="", + device_id="deviceId", + ) + + +class TestAsyncRecordings: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.list( + device_id="deviceId", + ) + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.list( + device_id="deviceId", + status="status", + type="type", + ) + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.list( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.list( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert_matches_type(Optional[RecordingListResponse], recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.list( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.delete( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.delete( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.delete( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.delete( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + await async_client.devices.recordings.with_raw_response.delete( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_start(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.start( + device_id="deviceId", + ) + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_start_with_all_params(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.start( + device_id="deviceId", + name="name", + retention_days=1, + types=["string"], + ) + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_start(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.start( + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_start(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.start( + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert_matches_type(RecordingStartResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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.recordings.with_raw_response.start( + device_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_status(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.status( + recording_id="recordingId", + device_id="deviceId", + ) + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_status(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.status( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_status(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.status( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert_matches_type(RecordingStatusResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_status(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.recordings.with_raw_response.status( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + await async_client.devices.recordings.with_raw_response.status( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_stop(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.stop( + recording_id="recordingId", + device_id="deviceId", + ) + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_stop(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.stop( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.stop( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert_matches_type(RecordingStopResponse, recording, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_stop(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.recordings.with_raw_response.stop( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + await async_client.devices.recordings.with_raw_response.stop( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_trajectory(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_trajectory(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_trajectory(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.trajectory( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_trajectory(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.recordings.with_raw_response.trajectory( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + await async_client.devices.recordings.with_raw_response.trajectory( + recording_id="", + device_id="deviceId", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_video(self, async_client: AsyncMobilerun) -> None: + recording = await async_client.devices.recordings.video( + recording_id="recordingId", + device_id="deviceId", + ) + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_video(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.recordings.with_raw_response.video( + recording_id="recordingId", + device_id="deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + recording = await response.parse() + assert recording is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_video(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.recordings.with_streaming_response.video( + recording_id="recordingId", + device_id="deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + recording = await response.parse() + assert recording is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_video(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.recordings.with_raw_response.video( + recording_id="recordingId", + device_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `recording_id` but received ''"): + await async_client.devices.recordings.with_raw_response.video( + recording_id="", + device_id="deviceId", + ) diff --git a/tests/api_resources/esims/__init__.py b/tests/api_resources/esims/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/esims/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/esims/test_messages.py b/tests/api_resources/esims/test_messages.py new file mode 100644 index 00000000..aa71f91d --- /dev/null +++ b/tests/api_resources/esims/test_messages.py @@ -0,0 +1,262 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMessages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + message = client.esims.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + message = client.esims.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + direction="all", + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + page=1, + page_size=1, + peer_key="x", + peer_number="xxx", + status="all", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.esims.messages.with_raw_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.esims.messages.with_streaming_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.esims.messages.with_raw_response.list( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_send(self, client: Mobilerun) -> None: + message = client.esims.messages.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_send_with_all_params(self, client: Mobilerun) -> None: + message = client.esims.messages.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + client_request_id="x", + delivery_report=True, + ) + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_send(self, client: Mobilerun) -> None: + response = client.esims.messages.with_raw_response.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_send(self, client: Mobilerun) -> None: + with client.esims.messages.with_streaming_response.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert_matches_type(MessageSendResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_send(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.esims.messages.with_raw_response.send( + id="", + body="x", + to="+15551230001", + ) + + +class TestAsyncMessages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + message = await async_client.esims.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + message = await async_client.esims.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + direction="all", + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + page=1, + page_size=1, + peer_key="x", + peer_number="xxx", + status="all", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.messages.with_raw_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.messages.with_streaming_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.esims.messages.with_raw_response.list( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_send(self, async_client: AsyncMobilerun) -> None: + message = await async_client.esims.messages.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_send_with_all_params(self, async_client: AsyncMobilerun) -> None: + message = await async_client.esims.messages.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + client_request_id="x", + delivery_report=True, + ) + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_send(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.messages.with_raw_response.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert_matches_type(MessageSendResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_send(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.messages.with_streaming_response.send( + id="550e8400-e29b-41d4-a716-446655440000", + body="x", + to="+15551230001", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert_matches_type(MessageSendResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_send(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.esims.messages.with_raw_response.send( + id="", + body="x", + to="+15551230001", + ) diff --git a/tests/api_resources/messages/__init__.py b/tests/api_resources/messages/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/messages/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/messages/test_conversations.py b/tests/api_resources/messages/test_conversations.py new file mode 100644 index 00000000..8ef6963b --- /dev/null +++ b/tests/api_resources/messages/test_conversations.py @@ -0,0 +1,188 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk._utils import parse_datetime +from mobilerun_sdk.types.messages import ( + ConversationListResponse, + ConversationMarkReadResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestConversations: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + conversation = client.messages.conversations.list() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + conversation = client.messages.conversations.list( + cursor_last_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + cursor_last_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + esim_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + limit=1, + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.messages.conversations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.messages.conversations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_mark_read(self, client: Mobilerun) -> None: + conversation = client.messages.conversations.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_mark_read(self, client: Mobilerun) -> None: + response = client.messages.conversations.with_raw_response.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = response.parse() + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_mark_read(self, client: Mobilerun) -> None: + with client.messages.conversations.with_streaming_response.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = response.parse() + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncConversations: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + conversation = await async_client.messages.conversations.list() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + conversation = await async_client.messages.conversations.list( + cursor_last_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + cursor_last_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + esim_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + limit=1, + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.messages.conversations.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = await response.parse() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.messages.conversations.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(ConversationListResponse, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_mark_read(self, async_client: AsyncMobilerun) -> None: + conversation = await async_client.messages.conversations.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_mark_read(self, async_client: AsyncMobilerun) -> None: + response = await async_client.messages.conversations.with_raw_response.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + conversation = await response.parse() + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_mark_read(self, async_client: AsyncMobilerun) -> None: + async with async_client.messages.conversations.with_streaming_response.mark_read( + peer_key="x", + up_to_message_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + up_to_occurred_at=parse_datetime("2019-12-27T18:11:19.117Z"), + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + conversation = await response.parse() + assert_matches_type(ConversationMarkReadResponse, conversation, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/numbers/__init__.py b/tests/api_resources/numbers/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/numbers/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/numbers/test_messages.py b/tests/api_resources/numbers/test_messages.py new file mode 100644 index 00000000..eb691c13 --- /dev/null +++ b/tests/api_resources/numbers/test_messages.py @@ -0,0 +1,133 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk._utils import parse_datetime +from mobilerun_sdk.types.numbers import MessageListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMessages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + message = client.numbers.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + message = client.numbers.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + direction="all", + page=1, + page_size=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.numbers.messages.with_raw_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.numbers.messages.with_streaming_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.numbers.messages.with_raw_response.list( + id="", + ) + + +class TestAsyncMessages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + message = await async_client.numbers.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + message = await async_client.numbers.messages.list( + id="550e8400-e29b-41d4-a716-446655440000", + direction="all", + page=1, + page_size=1, + since=parse_datetime("2019-12-27T18:11:19.117Z"), + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.messages.with_raw_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.messages.with_streaming_response.list( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.numbers.messages.with_raw_response.list( + id="", + ) diff --git a/tests/api_resources/store/__init__.py b/tests/api_resources/store/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/store/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/store/test_apps.py b/tests/api_resources/store/test_apps.py new file mode 100644 index 00000000..7935102a --- /dev/null +++ b/tests/api_resources/store/test_apps.py @@ -0,0 +1,270 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types.store import AppListResponse, AppRetrieveResponse, AppAddToWorkspaceResponse + +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="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Mobilerun) -> None: + app = client.store.apps.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Mobilerun) -> None: + response = client.store.apps.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Mobilerun) -> None: + with client.store.apps.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `app_id` but received ''"): + client.store.apps.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + app = client.store.apps.list() + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + app = client.store.apps.list( + category="category", + page=1, + page_size=1, + query="query", + ) + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.store.apps.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.store.apps.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppListResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_add_to_workspace(self, client: Mobilerun) -> None: + app = client.store.apps.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_add_to_workspace(self, client: Mobilerun) -> None: + response = client.store.apps.with_raw_response.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_add_to_workspace(self, client: Mobilerun) -> None: + with client.store.apps.with_streaming_response.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_add_to_workspace(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `app_id` but received ''"): + client.store.apps.with_raw_response.add_to_workspace( + "", + ) + + +class TestAsyncApps: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: + app = await async_client.store.apps.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: + response = await async_client.store.apps.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: + async with async_client.store.apps.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppRetrieveResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `app_id` but received ''"): + await async_client.store.apps.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + app = await async_client.store.apps.list() + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + app = await async_client.store.apps.list( + category="category", + page=1, + page_size=1, + query="query", + ) + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.store.apps.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppListResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.store.apps.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppListResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_add_to_workspace(self, async_client: AsyncMobilerun) -> None: + app = await async_client.store.apps.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_add_to_workspace(self, async_client: AsyncMobilerun) -> None: + response = await async_client.store.apps.with_raw_response.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_add_to_workspace(self, async_client: AsyncMobilerun) -> None: + async with async_client.store.apps.with_streaming_response.add_to_workspace( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppAddToWorkspaceResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_add_to_workspace(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `app_id` but received ''"): + await async_client.store.apps.with_raw_response.add_to_workspace( + "", + ) diff --git a/tests/api_resources/tasks/test_screenshots.py b/tests/api_resources/tasks/test_screenshots.py index 53eb4282..0c8724e9 100644 --- a/tests/api_resources/tasks/test_screenshots.py +++ b/tests/api_resources/tasks/test_screenshots.py @@ -9,7 +9,7 @@ from tests.utils import assert_matches_type from mobilerun_sdk import Mobilerun, AsyncMobilerun -from mobilerun_sdk.types.tasks import MediaResponse, ScreenshotListResponse +from mobilerun_sdk.types.tasks import ScreenshotListResponse, ScreenshotRetrieveResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -24,7 +24,7 @@ def test_method_retrieve(self, client: Mobilerun) -> None: index=0, task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -37,7 +37,7 @@ def test_raw_response_retrieve(self, client: Mobilerun) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" screenshot = response.parse() - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -50,7 +50,7 @@ def test_streaming_response_retrieve(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" screenshot = response.parse() - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) assert cast(Any, response.is_closed) is True @@ -118,7 +118,7 @@ async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: index=0, task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -131,7 +131,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" screenshot = await response.parse() - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -144,7 +144,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" screenshot = await response.parse() - assert_matches_type(MediaResponse, screenshot, path=["response"]) + assert_matches_type(ScreenshotRetrieveResponse, screenshot, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/tasks/test_ui_states.py b/tests/api_resources/tasks/test_ui_states.py index a7c2ba5d..d6c5998e 100644 --- a/tests/api_resources/tasks/test_ui_states.py +++ b/tests/api_resources/tasks/test_ui_states.py @@ -9,7 +9,7 @@ from tests.utils import assert_matches_type from mobilerun_sdk import Mobilerun, AsyncMobilerun -from mobilerun_sdk.types.tasks import MediaResponse, UiStateListResponse +from mobilerun_sdk.types.tasks import UiStateListResponse, UiStateRetrieveResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -24,7 +24,7 @@ def test_method_retrieve(self, client: Mobilerun) -> None: index=0, task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -37,7 +37,7 @@ def test_raw_response_retrieve(self, client: Mobilerun) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" ui_state = response.parse() - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -50,7 +50,7 @@ def test_streaming_response_retrieve(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" ui_state = response.parse() - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) assert cast(Any, response.is_closed) is True @@ -118,7 +118,7 @@ async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: index=0, task_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -131,7 +131,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" ui_state = await response.parse() - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -144,7 +144,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" ui_state = await response.parse() - assert_matches_type(MediaResponse, ui_state, path=["response"]) + assert_matches_type(UiStateRetrieveResponse, ui_state, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py new file mode 100644 index 00000000..8087dead --- /dev/null +++ b/tests/api_resources/test_agents.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import AgentListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAgents: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + agent = client.agents.list() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.agents.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + agent = response.parse() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.agents.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + agent = response.parse() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAgents: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + agent = await async_client.agents.list() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.agents.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + agent = await response.parse() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.agents.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + agent = await response.parse() + assert_matches_type(AgentListResponse, agent, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_app_events.py b/tests/api_resources/test_app_events.py new file mode 100644 index 00000000..041d503c --- /dev/null +++ b/tests/api_resources/test_app_events.py @@ -0,0 +1,192 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import AppEventListResponse, AppEventRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestAppEvents: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Mobilerun) -> None: + app_event = client.app_events.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Mobilerun) -> None: + response = client.app_events.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app_event = response.parse() + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Mobilerun) -> None: + with client.app_events.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app_event = response.parse() + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.app_events.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + app_event = client.app_events.list() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + app_event = client.app_events.list( + device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + event_type="eventType", + from_="from", + page=1, + page_size=1, + source="app", + to="to", + ) + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.app_events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app_event = response.parse() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.app_events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app_event = response.parse() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncAppEvents: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: + app_event = await async_client.app_events.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: + response = await async_client.app_events.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app_event = await response.parse() + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: + async with async_client.app_events.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app_event = await response.parse() + assert_matches_type(AppEventRetrieveResponse, app_event, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.app_events.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + app_event = await async_client.app_events.list() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + app_event = await async_client.app_events.list( + device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + event_type="eventType", + from_="from", + page=1, + page_size=1, + source="app", + to="to", + ) + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.app_events.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app_event = await response.parse() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.app_events.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app_event = await response.parse() + assert_matches_type(AppEventListResponse, app_event, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_apps.py b/tests/api_resources/test_apps.py index 9521800e..da9cde5f 100644 --- a/tests/api_resources/test_apps.py +++ b/tests/api_resources/test_apps.py @@ -15,6 +15,7 @@ AppRetrieveResponse, AppMarkFailedResponse, AppListVersionsResponse, + AppStorageUsageResponse, AppConfirmUploadResponse, AppCreateSignedUploadURLResponse, ) @@ -362,6 +363,34 @@ def test_path_params_mark_failed(self, client: Mobilerun) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_storage_usage(self, client: Mobilerun) -> None: + app = client.apps.storage_usage() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_storage_usage(self, client: Mobilerun) -> None: + response = client.apps.with_raw_response.storage_usage() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = response.parse() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_storage_usage(self, client: Mobilerun) -> None: + with client.apps.with_streaming_response.storage_usage() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = response.parse() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True + class TestAsyncApps: parametrize = pytest.mark.parametrize( @@ -704,3 +733,31 @@ async def test_path_params_mark_failed(self, async_client: AsyncMobilerun) -> No await async_client.apps.with_raw_response.mark_failed( "", ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_storage_usage(self, async_client: AsyncMobilerun) -> None: + app = await async_client.apps.storage_usage() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_storage_usage(self, async_client: AsyncMobilerun) -> None: + response = await async_client.apps.with_raw_response.storage_usage() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + app = await response.parse() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_storage_usage(self, async_client: AsyncMobilerun) -> None: + async with async_client.apps.with_streaming_response.storage_usage() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + app = await response.parse() + assert_matches_type(AppStorageUsageResponse, app, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_devices.py b/tests/api_resources/test_devices.py index f24b1ae4..19b6067c 100644 --- a/tests/api_resources/test_devices.py +++ b/tests/api_resources/test_devices.py @@ -10,10 +10,14 @@ from tests.utils import assert_matches_type from mobilerun_sdk import Mobilerun, AsyncMobilerun from mobilerun_sdk.types import ( - Device, DeviceListResponse, DeviceCountResponse, + DeviceCreateResponse, + DeviceSetNameResponse, + DeviceRetrieveResponse, + DeviceWaitReadyResponse, DeviceFingerprintResponse, + DeviceRetrieveCapabilitiesResponse, ) from mobilerun_sdk._utils import parse_datetime @@ -27,7 +31,7 @@ class TestDevices: @parametrize def test_method_create(self, client: Mobilerun) -> None: device = client.devices.create() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -88,7 +92,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None: }, timezone="timezone", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -98,7 +102,7 @@ def test_raw_response_create(self, client: Mobilerun) -> None: 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"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -108,7 +112,7 @@ def test_streaming_response_create(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -118,7 +122,7 @@ def test_method_retrieve(self, client: Mobilerun) -> None: device = client.devices.retrieve( "deviceId", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -130,7 +134,7 @@ def test_raw_response_retrieve(self, client: Mobilerun) -> None: 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"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -142,7 +146,7 @@ def test_streaming_response_retrieve(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -363,6 +367,90 @@ def test_path_params_reset(self, client: Mobilerun) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_resume(self, client: Mobilerun) -> None: + device = client.devices.resume( + "deviceId", + ) + assert device is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_resume(self, client: Mobilerun) -> None: + response = client.devices.with_raw_response.resume( + "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="Mock server tests are disabled") + @parametrize + def test_streaming_response_resume(self, client: Mobilerun) -> None: + with client.devices.with_streaming_response.resume( + "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="Mock server tests are disabled") + @parametrize + def test_path_params_resume(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.resume( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_capabilities(self, client: Mobilerun) -> None: + device = client.devices.retrieve_capabilities( + "deviceId", + ) + assert_matches_type(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_capabilities(self, client: Mobilerun) -> None: + response = client.devices.with_raw_response.retrieve_capabilities( + "deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + device = response.parse() + assert_matches_type(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_capabilities(self, client: Mobilerun) -> None: + with client.devices.with_streaming_response.retrieve_capabilities( + "deviceId", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + device = response.parse() + assert_matches_type(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve_capabilities(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_capabilities( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_set_name(self, client: Mobilerun) -> None: @@ -370,7 +458,7 @@ def test_method_set_name(self, client: Mobilerun) -> None: device_id="deviceId", name="x", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -383,7 +471,7 @@ def test_raw_response_set_name(self, client: Mobilerun) -> None: 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"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -396,7 +484,7 @@ def test_streaming_response_set_name(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -409,6 +497,48 @@ def test_path_params_set_name(self, client: Mobilerun) -> None: name="x", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_stop(self, client: Mobilerun) -> None: + device = client.devices.stop( + "deviceId", + ) + assert device is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_stop(self, client: Mobilerun) -> None: + response = client.devices.with_raw_response.stop( + "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="Mock server tests are disabled") + @parametrize + def test_streaming_response_stop(self, client: Mobilerun) -> None: + with client.devices.with_streaming_response.stop( + "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="Mock server tests are disabled") + @parametrize + def test_path_params_stop(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.stop( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_terminate(self, client: Mobilerun) -> None: @@ -467,7 +597,7 @@ def test_method_wait_ready(self, client: Mobilerun) -> None: device = client.devices.wait_ready( "deviceId", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -479,7 +609,7 @@ def test_raw_response_wait_ready(self, client: Mobilerun) -> None: 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"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -491,7 +621,7 @@ def test_streaming_response_wait_ready(self, client: Mobilerun) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -513,7 +643,7 @@ class TestAsyncDevices: @parametrize async def test_method_create(self, async_client: AsyncMobilerun) -> None: device = await async_client.devices.create() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -574,7 +704,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) }, timezone="timezone", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -584,7 +714,7 @@ async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None: 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"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -594,7 +724,7 @@ async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = await response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceCreateResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -604,7 +734,7 @@ async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: device = await async_client.devices.retrieve( "deviceId", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -616,7 +746,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None 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"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -628,7 +758,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = await response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceRetrieveResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -849,6 +979,90 @@ async def test_path_params_reset(self, async_client: AsyncMobilerun) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_resume(self, async_client: AsyncMobilerun) -> None: + device = await async_client.devices.resume( + "deviceId", + ) + assert device is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_resume(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.with_raw_response.resume( + "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="Mock server tests are disabled") + @parametrize + async def test_streaming_response_resume(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.with_streaming_response.resume( + "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="Mock server tests are disabled") + @parametrize + async def test_path_params_resume(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.resume( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_capabilities(self, async_client: AsyncMobilerun) -> None: + device = await async_client.devices.retrieve_capabilities( + "deviceId", + ) + assert_matches_type(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_capabilities(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.with_raw_response.retrieve_capabilities( + "deviceId", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + device = await response.parse() + assert_matches_type(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_capabilities(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.with_streaming_response.retrieve_capabilities( + "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(DeviceRetrieveCapabilitiesResponse, device, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve_capabilities(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_capabilities( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_set_name(self, async_client: AsyncMobilerun) -> None: @@ -856,7 +1070,7 @@ async def test_method_set_name(self, async_client: AsyncMobilerun) -> None: device_id="deviceId", name="x", ) - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -869,7 +1083,7 @@ async def test_raw_response_set_name(self, async_client: AsyncMobilerun) -> None 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"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -882,7 +1096,7 @@ async def test_streaming_response_set_name(self, async_client: AsyncMobilerun) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = await response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceSetNameResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True @@ -895,6 +1109,48 @@ async def test_path_params_set_name(self, async_client: AsyncMobilerun) -> None: name="x", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_stop(self, async_client: AsyncMobilerun) -> None: + device = await async_client.devices.stop( + "deviceId", + ) + assert device is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_stop(self, async_client: AsyncMobilerun) -> None: + response = await async_client.devices.with_raw_response.stop( + "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="Mock server tests are disabled") + @parametrize + async def test_streaming_response_stop(self, async_client: AsyncMobilerun) -> None: + async with async_client.devices.with_streaming_response.stop( + "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="Mock server tests are disabled") + @parametrize + async def test_path_params_stop(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.stop( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_terminate(self, async_client: AsyncMobilerun) -> None: @@ -953,7 +1209,7 @@ 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"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -965,7 +1221,7 @@ async def test_raw_response_wait_ready(self, async_client: AsyncMobilerun) -> No 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"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize @@ -977,7 +1233,7 @@ async def test_streaming_response_wait_ready(self, async_client: AsyncMobilerun) assert response.http_request.headers.get("X-Stainless-Lang") == "python" device = await response.parse() - assert_matches_type(Device, device, path=["response"]) + assert_matches_type(DeviceWaitReadyResponse, device, path=["response"]) assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_esims.py b/tests/api_resources/test_esims.py new file mode 100644 index 00000000..4040193e --- /dev/null +++ b/tests/api_resources/test_esims.py @@ -0,0 +1,933 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import ( + EsimListResponse, + EsimCreateResponse, + EsimImportResponse, + EsimUpdateResponse, + EsimInstallResponse, + EsimCapacityResponse, + EsimRetrieveResponse, + EsimSelectorResponse, + EsimInstallStatusResponse, + EsimConfirmPaymentResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestEsims: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Mobilerun) -> None: + esim = client.esims.create() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Mobilerun) -> None: + esim = client.esims.create( + idempotency_key="idempotencyKey", + ) + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Mobilerun) -> None: + esim = client.esims.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.esims.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Mobilerun) -> None: + esim = client.esims.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Mobilerun) -> None: + esim = client.esims.update( + id="550e8400-e29b-41d4-a716-446655440000", + msisdn="+33612345678", + name="Mom's phone", + ) + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.esims.with_raw_response.update( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + esim = client.esims.list() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + esim = client.esims.list( + mine="true", + page=1, + page_size=1, + status="all", + ) + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Mobilerun) -> None: + esim = client.esims.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert esim is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.esims.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_capacity(self, client: Mobilerun) -> None: + esim = client.esims.capacity() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_capacity(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.capacity() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_capacity(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.capacity() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_confirm_payment(self, client: Mobilerun) -> None: + esim = client.esims.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_confirm_payment(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_confirm_payment(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_confirm_payment(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.esims.with_raw_response.confirm_payment( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_import(self, client: Mobilerun) -> None: + esim = client.esims.import_() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_import_with_all_params(self, client: Mobilerun) -> None: + esim = client.esims.import_( + auto_install=True, + carrier_name="carrierName", + confirmation_code="confirmationCode", + country_code="countryCode", + device_id="physedge-dev-8f3a2c", + idempotency_key="x", + lpa_code="LPA:1$smdp.example.com$QR-MATCH-1", + matching_id="matchingId", + msisdn="+33612345678", + name="Mom's phone", + notes="notes", + smdp_address="smdp.example.com", + ) + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_import(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.import_() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_import(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.import_() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_install(self, client: Mobilerun) -> None: + esim = client.esims.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_install_with_all_params(self, client: Mobilerun) -> None: + esim = client.esims.install( + id="550e8400-e29b-41d4-a716-446655440000", + device_id="physedge-dev-8f3a2c", + ) + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_install(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_install(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.esims.with_raw_response.install( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_install_status(self, client: Mobilerun) -> None: + esim = client.esims.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_install_status(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_install_status(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_install_status(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.esims.with_raw_response.install_status( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_selector(self, client: Mobilerun) -> None: + esim = client.esims.selector() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_selector(self, client: Mobilerun) -> None: + response = client.esims.with_raw_response.selector() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = response.parse() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_selector(self, client: Mobilerun) -> None: + with client.esims.with_streaming_response.selector() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = response.parse() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncEsims: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.create() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.create( + idempotency_key="idempotencyKey", + ) + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimCreateResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.esims.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.update( + id="550e8400-e29b-41d4-a716-446655440000", + msisdn="+33612345678", + name="Mom's phone", + ) + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.update( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimUpdateResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.esims.with_raw_response.update( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.list() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.list( + mine="true", + page=1, + page_size=1, + status="all", + ) + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimListResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert esim is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert esim is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.esims.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_capacity(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.capacity() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_capacity(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.capacity() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_capacity(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.capacity() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimCapacityResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_confirm_payment(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_confirm_payment(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_confirm_payment(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.confirm_payment( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_confirm_payment(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.esims.with_raw_response.confirm_payment( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_import(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.import_() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_import_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.import_( + auto_install=True, + carrier_name="carrierName", + confirmation_code="confirmationCode", + country_code="countryCode", + device_id="physedge-dev-8f3a2c", + idempotency_key="x", + lpa_code="LPA:1$smdp.example.com$QR-MATCH-1", + matching_id="matchingId", + msisdn="+33612345678", + name="Mom's phone", + notes="notes", + smdp_address="smdp.example.com", + ) + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_import(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.import_() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_import(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.import_() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimImportResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_install(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_install_with_all_params(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.install( + id="550e8400-e29b-41d4-a716-446655440000", + device_id="physedge-dev-8f3a2c", + ) + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_install(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_install(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.install( + id="550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimInstallResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.esims.with_raw_response.install( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_install_status(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_install_status(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_install_status(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.install_status( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_install_status(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.esims.with_raw_response.install_status( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_selector(self, async_client: AsyncMobilerun) -> None: + esim = await async_client.esims.selector() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_selector(self, async_client: AsyncMobilerun) -> None: + response = await async_client.esims.with_raw_response.selector() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + esim = await response.parse() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_selector(self, async_client: AsyncMobilerun) -> None: + async with async_client.esims.with_streaming_response.selector() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + esim = await response.parse() + assert_matches_type(EsimSelectorResponse, esim, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_messages.py b/tests/api_resources/test_messages.py new file mode 100644 index 00000000..a3d35670 --- /dev/null +++ b/tests/api_resources/test_messages.py @@ -0,0 +1,110 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import MessageListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMessages: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + message = client.messages.list() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + message = client.messages.list( + direction="all", + esim_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + page=1, + page_size=1, + peer_key="x", + peer_number="xxx", + status="all", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.messages.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.messages.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncMessages: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + message = await async_client.messages.list() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + message = await async_client.messages.list( + direction="all", + esim_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + page=1, + page_size=1, + peer_key="x", + peer_number="xxx", + status="all", + ) + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.messages.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.messages.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + message = await response.parse() + assert_matches_type(MessageListResponse, message, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_notifications.py b/tests/api_resources/test_notifications.py new file mode 100644 index 00000000..c8180d64 --- /dev/null +++ b/tests/api_resources/test_notifications.py @@ -0,0 +1,208 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import ( + NotificationCatalogResponse, + NotificationGetPreferencesResponse, + NotificationUpdatePreferencesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNotifications: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_catalog(self, client: Mobilerun) -> None: + notification = client.notifications.catalog() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_catalog(self, client: Mobilerun) -> None: + response = client.notifications.with_raw_response.catalog() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = response.parse() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_catalog(self, client: Mobilerun) -> None: + with client.notifications.with_streaming_response.catalog() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = response.parse() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_get_preferences(self, client: Mobilerun) -> None: + notification = client.notifications.get_preferences() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_get_preferences(self, client: Mobilerun) -> None: + response = client.notifications.with_raw_response.get_preferences() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = response.parse() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_get_preferences(self, client: Mobilerun) -> None: + with client.notifications.with_streaming_response.get_preferences() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = response.parse() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update_preferences(self, client: Mobilerun) -> None: + notification = client.notifications.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update_preferences(self, client: Mobilerun) -> None: + response = client.notifications.with_raw_response.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = response.parse() + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update_preferences(self, client: Mobilerun) -> None: + with client.notifications.with_streaming_response.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = response.parse() + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncNotifications: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_catalog(self, async_client: AsyncMobilerun) -> None: + notification = await async_client.notifications.catalog() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_catalog(self, async_client: AsyncMobilerun) -> None: + response = await async_client.notifications.with_raw_response.catalog() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = await response.parse() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_catalog(self, async_client: AsyncMobilerun) -> None: + async with async_client.notifications.with_streaming_response.catalog() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = await response.parse() + assert_matches_type(NotificationCatalogResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_get_preferences(self, async_client: AsyncMobilerun) -> None: + notification = await async_client.notifications.get_preferences() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_get_preferences(self, async_client: AsyncMobilerun) -> None: + response = await async_client.notifications.with_raw_response.get_preferences() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = await response.parse() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_get_preferences(self, async_client: AsyncMobilerun) -> None: + async with async_client.notifications.with_streaming_response.get_preferences() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = await response.parse() + assert_matches_type(NotificationGetPreferencesResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update_preferences(self, async_client: AsyncMobilerun) -> None: + notification = await async_client.notifications.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update_preferences(self, async_client: AsyncMobilerun) -> None: + response = await async_client.notifications.with_raw_response.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + notification = await response.parse() + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update_preferences(self, async_client: AsyncMobilerun) -> None: + async with async_client.notifications.with_streaming_response.update_preferences( + muted_types=["workflow.run.running", "task.run.running"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + notification = await response.parse() + assert_matches_type(NotificationUpdatePreferencesResponse, notification, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_numbers.py b/tests/api_resources/test_numbers.py new file mode 100644 index 00000000..bf4d09de --- /dev/null +++ b/tests/api_resources/test_numbers.py @@ -0,0 +1,463 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import ( + NumberListResponse, + NumberCreateResponse, + NumberDeleteResponse, + NumberPurposesResponse, + NumberRetrieveResponse, + NumberCountriesResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestNumbers: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Mobilerun) -> None: + number = client.numbers.create() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Mobilerun) -> None: + number = client.numbers.create( + billing_preference="included", + country="de", + purpose="telegram", + idempotency_key="x", + ) + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Mobilerun) -> None: + number = client.numbers.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.numbers.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Mobilerun) -> None: + number = client.numbers.list() + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Mobilerun) -> None: + number = client.numbers.list( + page=1, + page_size=1, + ) + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberListResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Mobilerun) -> None: + number = client.numbers.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + client.numbers.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_countries(self, client: Mobilerun) -> None: + number = client.numbers.countries() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_countries(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.countries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_countries(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.countries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_purposes(self, client: Mobilerun) -> None: + number = client.numbers.purposes() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_purposes(self, client: Mobilerun) -> None: + response = client.numbers.with_raw_response.purposes() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = response.parse() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_purposes(self, client: Mobilerun) -> None: + with client.numbers.with_streaming_response.purposes() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = response.parse() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncNumbers: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.create() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.create( + billing_preference="included", + country="de", + purpose="telegram", + idempotency_key="x", + ) + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.create() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.create() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberCreateResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.retrieve( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberRetrieveResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.numbers.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.list() + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.list( + page=1, + page_size=1, + ) + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberListResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberListResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.delete( + "550e8400-e29b-41d4-a716-446655440000", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberDeleteResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server 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 `id` but received ''"): + await async_client.numbers.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_countries(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.countries() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_countries(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.countries() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_countries(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.countries() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberCountriesResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_purposes(self, async_client: AsyncMobilerun) -> None: + number = await async_client.numbers.purposes() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_purposes(self, async_client: AsyncMobilerun) -> None: + response = await async_client.numbers.with_raw_response.purposes() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + number = await response.parse() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_purposes(self, async_client: AsyncMobilerun) -> None: + async with async_client.numbers.with_streaming_response.purposes() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + number = await response.parse() + assert_matches_type(NumberPurposesResponse, number, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_store.py b/tests/api_resources/test_store.py new file mode 100644 index 00000000..705fc532 --- /dev/null +++ b/tests/api_resources/test_store.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from tests.utils import assert_matches_type +from mobilerun_sdk import Mobilerun, AsyncMobilerun +from mobilerun_sdk.types import StoreCategoriesResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestStore: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_categories(self, client: Mobilerun) -> None: + store = client.store.categories() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_categories(self, client: Mobilerun) -> None: + response = client.store.with_raw_response.categories() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + store = response.parse() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_categories(self, client: Mobilerun) -> None: + with client.store.with_streaming_response.categories() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + store = response.parse() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncStore: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_categories(self, async_client: AsyncMobilerun) -> None: + store = await async_client.store.categories() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_categories(self, async_client: AsyncMobilerun) -> None: + response = await async_client.store.with_raw_response.categories() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + store = await response.parse() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_categories(self, async_client: AsyncMobilerun) -> None: + async with async_client.store.with_streaming_response.categories() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + store = await response.parse() + assert_matches_type(StoreCategoriesResponse, store, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/workflows/test_executions.py b/tests/api_resources/workflows/test_executions.py index 34ee5b36..7b24f4c0 100644 --- a/tests/api_resources/workflows/test_executions.py +++ b/tests/api_resources/workflows/test_executions.py @@ -11,6 +11,7 @@ from mobilerun_sdk import Mobilerun, AsyncMobilerun from mobilerun_sdk.types.workflows import ( ExecutionListResponse, + ExecutionAbortResponse, ExecutionRetrieveResponse, ExecutionGetMetricsResponse, ) @@ -108,6 +109,48 @@ def test_streaming_response_list(self, client: Mobilerun) -> None: assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_abort(self, client: Mobilerun) -> None: + execution = client.workflows.executions.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_abort(self, client: Mobilerun) -> None: + response = client.workflows.executions.with_raw_response.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = response.parse() + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_abort(self, client: Mobilerun) -> None: + with client.workflows.executions.with_streaming_response.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = response.parse() + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_abort(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + client.workflows.executions.with_raw_response.abort( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_get_metrics(self, client: Mobilerun) -> None: @@ -240,6 +283,48 @@ async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> No assert cast(Any, response.is_closed) is True + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_abort(self, async_client: AsyncMobilerun) -> None: + execution = await async_client.workflows.executions.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_abort(self, async_client: AsyncMobilerun) -> None: + response = await async_client.workflows.executions.with_raw_response.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + execution = await response.parse() + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_abort(self, async_client: AsyncMobilerun) -> None: + async with async_client.workflows.executions.with_streaming_response.abort( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + execution = await response.parse() + assert_matches_type(ExecutionAbortResponse, execution, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_abort(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): + await async_client.workflows.executions.with_raw_response.abort( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_get_metrics(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/api_resources/workflows/test_flows.py b/tests/api_resources/workflows/test_flows.py index 7af69e31..0cbbda1c 100644 --- a/tests/api_resources/workflows/test_flows.py +++ b/tests/api_resources/workflows/test_flows.py @@ -14,9 +14,11 @@ FlowCloneResponse, FlowCreateResponse, FlowDeleteResponse, + FlowDryRunResponse, FlowUpdateResponse, FlowUnblockResponse, FlowRetrieveResponse, + FlowListRepairsResponse, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -362,6 +364,99 @@ def test_path_params_clone(self, client: Mobilerun) -> None: flow_id="", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_dry_run(self, client: Mobilerun) -> None: + flow = client.workflows.flows.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_dry_run_with_all_params(self, client: Mobilerun) -> None: + flow = client.workflows.flows.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + payload={"foo": "bar"}, + ) + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_dry_run(self, client: Mobilerun) -> None: + response = client.workflows.flows.with_raw_response.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flow = response.parse() + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_dry_run(self, client: Mobilerun) -> None: + with client.workflows.flows.with_streaming_response.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flow = response.parse() + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_dry_run(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"): + client.workflows.flows.with_raw_response.dry_run( + flow_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_repairs(self, client: Mobilerun) -> None: + flow = client.workflows.flows.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list_repairs(self, client: Mobilerun) -> None: + response = client.workflows.flows.with_raw_response.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flow = response.parse() + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list_repairs(self, client: Mobilerun) -> None: + with client.workflows.flows.with_streaming_response.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flow = response.parse() + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list_repairs(self, client: Mobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"): + client.workflows.flows.with_raw_response.list_repairs( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_unblock(self, client: Mobilerun) -> None: @@ -747,6 +842,99 @@ async def test_path_params_clone(self, async_client: AsyncMobilerun) -> None: flow_id="", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_dry_run(self, async_client: AsyncMobilerun) -> None: + flow = await async_client.workflows.flows.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_dry_run_with_all_params(self, async_client: AsyncMobilerun) -> None: + flow = await async_client.workflows.flows.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + payload={"foo": "bar"}, + ) + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_dry_run(self, async_client: AsyncMobilerun) -> None: + response = await async_client.workflows.flows.with_raw_response.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flow = await response.parse() + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_dry_run(self, async_client: AsyncMobilerun) -> None: + async with async_client.workflows.flows.with_streaming_response.dry_run( + flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flow = await response.parse() + assert_matches_type(FlowDryRunResponse, flow, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_dry_run(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"): + await async_client.workflows.flows.with_raw_response.dry_run( + flow_id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_repairs(self, async_client: AsyncMobilerun) -> None: + flow = await async_client.workflows.flows.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list_repairs(self, async_client: AsyncMobilerun) -> None: + response = await async_client.workflows.flows.with_raw_response.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + flow = await response.parse() + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list_repairs(self, async_client: AsyncMobilerun) -> None: + async with async_client.workflows.flows.with_streaming_response.list_repairs( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + flow = await response.parse() + assert_matches_type(FlowListRepairsResponse, flow, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list_repairs(self, async_client: AsyncMobilerun) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"): + await async_client.workflows.flows.with_raw_response.list_repairs( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_unblock(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/test_client.py b/tests/test_client.py index bc773737..9af846f0 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -884,20 +884,20 @@ def test_parse_retry_after_header( @mock.patch("mobilerun_sdk._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("/devices").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - client.tasks.with_streaming_response.list().__enter__() + client.devices.with_streaming_response.list().__enter__() assert _get_open_connections(client) == 0 @mock.patch("mobilerun_sdk._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("/devices").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - client.tasks.with_streaming_response.list().__enter__() + client.devices.with_streaming_response.list().__enter__() assert _get_open_connections(client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -924,9 +924,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("/devices").mock(side_effect=retry_handler) - response = client.tasks.with_raw_response.list() + response = client.devices.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 @@ -948,9 +948,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("/devices").mock(side_effect=retry_handler) - response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()}) + response = client.devices.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()}) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -971,9 +971,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("/devices").mock(side_effect=retry_handler) - response = client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"}) + response = client.devices.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"}) assert response.http_request.headers.get("x-stainless-retry-count") == "42" @@ -1825,10 +1825,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").mock(side_effect=httpx.TimeoutException("Test timeout error")) + respx_mock.get("/devices").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await async_client.tasks.with_streaming_response.list().__aenter__() + await async_client.devices.with_streaming_response.list().__aenter__() assert _get_open_connections(async_client) == 0 @@ -1837,10 +1837,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").mock(return_value=httpx.Response(500)) + respx_mock.get("/devices").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await async_client.tasks.with_streaming_response.list().__aenter__() + await async_client.devices.with_streaming_response.list().__aenter__() assert _get_open_connections(async_client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1867,9 +1867,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("/devices").mock(side_effect=retry_handler) - response = await client.tasks.with_raw_response.list() + response = await client.devices.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 @@ -1891,9 +1891,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("/devices").mock(side_effect=retry_handler) - response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()}) + response = await client.devices.with_raw_response.list(extra_headers={"x-stainless-retry-count": Omit()}) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -1914,9 +1914,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("/devices").mock(side_effect=retry_handler) - response = await client.tasks.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"}) + response = await client.devices.with_raw_response.list(extra_headers={"x-stainless-retry-count": "42"}) assert response.http_request.headers.get("x-stainless-retry-count") == "42" From 3ad4fe07f3eab5de280a8cce0e801879977d58f4 Mon Sep 17 00:00:00 2001 From: stlc-bot Date: Thu, 20 Aug 2026 09:42:53 +0000 Subject: [PATCH 4/5] chore: release 5.2.1 Release-As: 5.2.1 From 392973e820705804333c9c3fa3d00f8f3ee90e38 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2026 09:42:58 +0000 Subject: [PATCH 5/5] release: 5.3.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 13 +++++++++++++ pyproject.toml | 2 +- src/mobilerun_sdk/_version.py | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b29b3b64..41010749 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.2.0" + ".": "5.3.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 18fdcffa..f167e268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 5.3.0 (2026-08-20) + +Full Changelog: [v5.2.0...v5.3.0](https://github.com/droidrun/mobilerun-sdk-python/compare/v5.2.0...v5.3.0) + +### Features + +* **bootstrap:** repo-driven STLC pipeline ([8bd21c0](https://github.com/droidrun/mobilerun-sdk-python/commit/8bd21c08cd24053976d4fe7e3b15717b3f30379a)) + + +### Bug Fixes + +* **ci:** serialize release-please, ff main, drop prerelease ([332dcb7](https://github.com/droidrun/mobilerun-sdk-python/commit/332dcb7a384078489bae09fb7005a15b72b86246)) + ## 5.2.0 (2026-08-13) Full Changelog: [v5.1.0...v5.2.0](https://github.com/droidrun/mobilerun-sdk-python/compare/v5.1.0...v5.2.0) diff --git a/pyproject.toml b/pyproject.toml index f5a20606..2511b3cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mobilerun-sdk" -version = "5.2.0" +version = "5.3.0" description = "The official Python library for the mobilerun API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/mobilerun_sdk/_version.py b/src/mobilerun_sdk/_version.py index 76bc230d..c881f1c5 100644 --- a/src/mobilerun_sdk/_version.py +++ b/src/mobilerun_sdk/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "mobilerun_sdk" -__version__ = "5.2.0" # x-release-please-version +__version__ = "5.3.0" # x-release-please-version