diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06b9186..a908819 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -41,7 +41,7 @@ jobs: permissions: contents: read id-token: write - runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -78,7 +78,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/dedalus-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index da59f99..2aca35a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.4.0" + ".": "0.5.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index bc3166c..6d1924d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 32 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs/dedalus-a63ad804ae8ee532d57afae307595dae02d2a6924f83657430b3579193560775.yml -openapi_spec_hash: ccb02923079d91569a17162c88da590b -config_hash: 0e31b0b75cafdbc25febc2b7ca219799 +configured_endpoints: 17 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs/dedalus-c0e28b234478af75f61bcf42f5f32818d96ec93b1d8239fa0ff1c801c0e4b64f.yml +openapi_spec_hash: a70c391bb0957fc90c5dbf251de8afe4 +config_hash: fa45a5bf161b7291cb5ea20c2da83cc0 diff --git a/CHANGELOG.md b/CHANGELOG.md index f7ec47b..6df1404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.5.0 (2026-09-01) + +Full Changelog: [v0.4.0...v0.5.0](https://github.com/dedalus-labs/dedalus-python/compare/v0.4.0...v0.5.0) + +### ⚠ BREAKING CHANGES + +* **api:** regenerate SDKs from the current public DCS contract + +### Features + +* **api:** regenerate SDKs from the current public DCS contract ([04208ef](https://github.com/dedalus-labs/dedalus-python/commit/04208ef05cb07426d68717abb57835e089b76205)) +* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([6acb1d3](https://github.com/dedalus-labs/dedalus-python/commit/6acb1d303d2a07cf6c01f63005a4f98541c47f40)) + + +### Bug Fixes + +* **auth:** prioritize first auth header ([81f3c28](https://github.com/dedalus-labs/dedalus-python/commit/81f3c288b2ae2e97046344177500714e1e4ce6be)) +* **internal:** resolve build failures ([c10ce00](https://github.com/dedalus-labs/dedalus-python/commit/c10ce00180c146772ec9f390e3d058a1d9462082)) + + +### Chores + +* **internal:** allow the mock server port to be set with STAINLESS_MOCK_PORT ([aa8a0ee](https://github.com/dedalus-labs/dedalus-python/commit/aa8a0ee9f29ad6fa93a917baba1ab0ffaebb6959)) + ## 0.4.0 (2026-05-12) Full Changelog: [v0.3.0...v0.4.0](https://github.com/dedalus-labs/dedalus-python/compare/v0.3.0...v0.4.0) diff --git a/README.md b/README.md index 7615cb4..0d2e4f5 100644 --- a/README.md +++ b/README.md @@ -118,36 +118,6 @@ async def main() -> None: asyncio.run(main()) ``` -## Streaming responses - -We provide support for streaming responses using Server Side Events (SSE). - -```python -from dedalus_sdk import Dedalus - -client = Dedalus() - -stream = client.machines.watch( - machine_id="dm-3", -) -for machine in stream: - print(machine.machine_id) -``` - -The async client uses the exact same interface. - -```python -from dedalus_sdk import AsyncDedalus - -client = AsyncDedalus() - -stream = await client.machines.watch( - machine_id="dm-3", -) -async for machine in stream: - print(machine.machine_id) -``` - ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: diff --git a/api.md b/api.md index 0f1d5dd..7941ddf 100644 --- a/api.md +++ b/api.md @@ -1,23 +1,3 @@ -# Usage - -Types: - -```python -from dedalus_sdk.types import ( - MachineComputeUsage, - MachineComputeUsageRow, - MachineStorageUsage, - MachineStorageUsageRow, - OrgUsage, -) -``` - -Methods: - -- client.usage.retrieve(\*\*params) -> OrgUsage -- client.usage.machine_compute(\*\*params) -> MachineComputeUsage -- client.usage.machine_storage(\*\*params) -> MachineStorageUsage - # Machines Types: @@ -30,48 +10,19 @@ from dedalus_sdk.types import ( MachineList, MachineListItem, UpdateParams, + MachineRetrieveResponse, ) ``` Methods: - client.machines.create(\*\*params) -> Machine -- client.machines.retrieve(\*, machine_id) -> Machine +- client.machines.retrieve(\*, machine_id) -> MachineRetrieveResponse - client.machines.update(\*, machine_id, \*\*params) -> Machine - client.machines.list(\*\*params) -> SyncCursorPage[MachineListItem] - client.machines.delete(\*, machine_id) -> Machine - client.machines.sleep(\*, machine_id) -> Machine - client.machines.wake(\*, machine_id) -> Machine -- client.machines.watch(\*, machine_id) -> Machine - -## Artifacts - -Types: - -```python -from dedalus_sdk.types.machines import Artifact, ArtifactList -``` - -Methods: - -- client.machines.artifacts.retrieve(\*, machine_id, artifact_id) -> Artifact -- client.machines.artifacts.list(\*, machine_id, \*\*params) -> SyncCursorPage[Artifact] -- client.machines.artifacts.delete(\*, machine_id, artifact_id) -> Artifact - -## Previews - -Types: - -```python -from dedalus_sdk.types.machines import Preview, PreviewCreateParams, PreviewList -``` - -Methods: - -- client.machines.previews.create(\*, machine_id, \*\*params) -> Preview -- client.machines.previews.retrieve(\*, machine_id, preview_id) -> Preview -- client.machines.previews.list(\*, machine_id, \*\*params) -> SyncCursorPage[Preview] -- client.machines.previews.delete(\*, machine_id, preview_id) -> Preview ## SSH @@ -118,29 +69,3 @@ Methods: - client.machines.executions.delete(\*, machine_id, execution_id) -> Execution - client.machines.executions.events(\*, machine_id, execution_id, \*\*params) -> SyncCursorPage[ExecutionEvent] - client.machines.executions.output(\*, machine_id, execution_id) -> ExecutionOutput - -## Terminals - -Types: - -```python -from dedalus_sdk.types.machines import ( - Terminal, - TerminalClientEvent, - TerminalClosedEvent, - TerminalCreateParams, - TerminalErrorEvent, - TerminalInputEvent, - TerminalList, - TerminalOutputEvent, - TerminalResizeEvent, - TerminalServerEvent, -) -``` - -Methods: - -- client.machines.terminals.create(\*, machine_id, \*\*params) -> Terminal -- client.machines.terminals.retrieve(\*, machine_id, terminal_id) -> Terminal -- client.machines.terminals.list(\*, machine_id, \*\*params) -> SyncCursorPage[Terminal] -- client.machines.terminals.delete(\*, machine_id, terminal_id) -> Terminal diff --git a/pyproject.toml b/pyproject.toml index 9fa189c..5e91b1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dedalus-sdk" -version = "0.4.0" +version = "0.5.0" description = "The official Python library for the Dedalus API" dynamic = ["readme"] license = "MIT" @@ -42,7 +42,6 @@ Repository = "https://github.com/dedalus-labs/dedalus-python" [project.optional-dependencies] aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] -websockets = ["websockets >= 13, < 16"] [tool.uv] managed = true diff --git a/scripts/lint b/scripts/lint index 5887ad5..371f4fa 100755 --- a/scripts/lint +++ b/scripts/lint @@ -13,7 +13,7 @@ else fi echo "==> Running pyright" -uv run pyright +uv run pyright -p . echo "==> Running mypy" uv run mypy . diff --git a/scripts/mock b/scripts/mock index 9c7c439..6376077 100755 --- a/scripts/mock +++ b/scripts/mock @@ -4,6 +4,11 @@ set -e cd "$(dirname "$0")/.." +if [ "$1" == "--install" ]; then + npm exec --package=@stdy/cli@0.22.1 -- steady --version + exit 0 +fi + if [[ -n "$1" && "$1" != '--'* ]]; then URL="$1" shift @@ -20,16 +25,18 @@ fi echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec +MOCK_PORT="${STAINLESS_MOCK_PORT:-4010}" + if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout npm exec --package=@stdy/cli@0.22.1 -- steady --version - npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p "$MOCK_PORT" --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" attempts=0 - while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + while ! curl --silent --fail "http://127.0.0.1:$MOCK_PORT/_x-steady/health" >/dev/null 2>&1; do if ! kill -0 $! 2>/dev/null; then echo cat .stdy.log @@ -48,5 +55,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p "$MOCK_PORT" --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index f371e71..caf18b7 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,10 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color +MOCK_PORT="${STAINLESS_MOCK_PORT:-4010}" + function steady_is_running() { - curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 + curl --silent "http://127.0.0.1:$MOCK_PORT/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -27,7 +29,7 @@ function is_overriding_api_base_url() { if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT + trap 'kill_server_on_port "$MOCK_PORT"' EXIT # Start the dev server ./scripts/mock --daemon @@ -43,7 +45,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p $MOCK_PORT --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 @@ -52,6 +54,10 @@ else echo fi +if [ -n "${STAINLESS_MOCK_PORT:-}" ] && ! is_overriding_api_base_url ; then + export TEST_API_BASE_URL="http://127.0.0.1:$MOCK_PORT" +fi + export DEFER_PYDANTIC_BUILD=false # Note that we need to specify the patch version here so that uv diff --git a/src/dedalus_sdk/__init__.py b/src/dedalus_sdk/__init__.py index 2aa7c7c..140521a 100644 --- a/src/dedalus_sdk/__init__.py +++ b/src/dedalus_sdk/__init__.py @@ -23,14 +23,11 @@ AuthenticationError, InternalServerError, PermissionDeniedError, - WebSocketQueueFullError, UnprocessableEntityError, APIResponseValidationError, - WebSocketConnectionClosedError, ) from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging -from .types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides __all__ = [ "types", @@ -74,10 +71,6 @@ "DefaultHttpxClient", "DefaultAsyncHttpxClient", "DefaultAioHttpClient", - "ReconnectingEvent", - "ReconnectingOverrides", - "WebSocketQueueFullError", - "WebSocketConnectionClosedError", ] if not _t.TYPE_CHECKING: diff --git a/src/dedalus_sdk/_client.py b/src/dedalus_sdk/_client.py index c6dc994..53fbd0e 100644 --- a/src/dedalus_sdk/_client.py +++ b/src/dedalus_sdk/_client.py @@ -37,8 +37,7 @@ ) if TYPE_CHECKING: - from .resources import usage, machines - from .resources.usage import UsageResource, AsyncUsageResource + from .resources import machines from .resources.machines.machines import MachinesResource, AsyncMachinesResource __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Dedalus", "AsyncDedalus", "Client", "AsyncClient"] @@ -50,14 +49,6 @@ class Dedalus(SyncAPIClient): x_api_key: str | None dedalus_org_id: str | None - websocket_base_url: str | httpx.URL | None - """Base URL for WebSocket connections. - - If not specified, the default base URL will be used, with 'wss://' replacing the - 'http://' or 'https://' scheme. For example: 'http://example.com' becomes - 'wss://example.com' - """ - def __init__( self, *, @@ -65,7 +56,6 @@ def __init__( x_api_key: str | None = None, dedalus_org_id: str | None = None, base_url: str | httpx.URL | None = None, - websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -103,8 +93,6 @@ def __init__( dedalus_org_id = os.environ.get("DEDALUS_ORG_ID") self.dedalus_org_id = dedalus_org_id - self.websocket_base_url = websocket_base_url - if base_url is None: base_url = os.environ.get("DEDALUS_BASE_URL") if base_url is None: @@ -132,14 +120,6 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self._default_stream_cls = Stream - - @cached_property - def usage(self) -> UsageResource: - from .resources.usage import UsageResource - - return UsageResource(self) - @cached_property def machines(self) -> MachinesResource: from .resources.machines import MachinesResource @@ -161,10 +141,14 @@ def qs(self) -> Querystring: @override def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: - return { - **(self._api_key_auth if security.get("api_key_auth", False) else {}), - **(self._bearer_auth if security.get("bearer_auth", False) else {}), - } + headers: dict[str, str] = {} + if security.get("api_key_auth", False): + for key, value in self._api_key_auth.items(): + headers.setdefault(key, value) + if security.get("bearer_auth", False): + for key, value in self._bearer_auth.items(): + headers.setdefault(key, value) + return headers @property def _api_key_auth(self) -> dict[str, str]: @@ -208,7 +192,6 @@ def copy( api_key: str | None = None, x_api_key: str | None = None, dedalus_org_id: str | None = None, - websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, @@ -245,7 +228,6 @@ def copy( api_key=api_key or self.api_key, x_api_key=x_api_key or self.x_api_key, dedalus_org_id=dedalus_org_id or self.dedalus_org_id, - websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -299,14 +281,6 @@ class AsyncDedalus(AsyncAPIClient): x_api_key: str | None dedalus_org_id: str | None - websocket_base_url: str | httpx.URL | None - """Base URL for WebSocket connections. - - If not specified, the default base URL will be used, with 'wss://' replacing the - 'http://' or 'https://' scheme. For example: 'http://example.com' becomes - 'wss://example.com' - """ - def __init__( self, *, @@ -314,7 +288,6 @@ def __init__( x_api_key: str | None = None, dedalus_org_id: str | None = None, base_url: str | httpx.URL | None = None, - websocket_base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, @@ -352,8 +325,6 @@ def __init__( dedalus_org_id = os.environ.get("DEDALUS_ORG_ID") self.dedalus_org_id = dedalus_org_id - self.websocket_base_url = websocket_base_url - if base_url is None: base_url = os.environ.get("DEDALUS_BASE_URL") if base_url is None: @@ -381,14 +352,6 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self._default_stream_cls = AsyncStream - - @cached_property - def usage(self) -> AsyncUsageResource: - from .resources.usage import AsyncUsageResource - - return AsyncUsageResource(self) - @cached_property def machines(self) -> AsyncMachinesResource: from .resources.machines import AsyncMachinesResource @@ -410,10 +373,14 @@ def qs(self) -> Querystring: @override def _auth_headers(self, security: SecurityOptions) -> dict[str, str]: - return { - **(self._api_key_auth if security.get("api_key_auth", False) else {}), - **(self._bearer_auth if security.get("bearer_auth", False) else {}), - } + headers: dict[str, str] = {} + if security.get("api_key_auth", False): + for key, value in self._api_key_auth.items(): + headers.setdefault(key, value) + if security.get("bearer_auth", False): + for key, value in self._bearer_auth.items(): + headers.setdefault(key, value) + return headers @property def _api_key_auth(self) -> dict[str, str]: @@ -457,7 +424,6 @@ def copy( api_key: str | None = None, x_api_key: str | None = None, dedalus_org_id: str | None = None, - websocket_base_url: str | httpx.URL | None = None, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, @@ -494,7 +460,6 @@ def copy( api_key=api_key or self.api_key, x_api_key=x_api_key or self.x_api_key, dedalus_org_id=dedalus_org_id or self.dedalus_org_id, - websocket_base_url=websocket_base_url or self.websocket_base_url, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -548,12 +513,6 @@ class DedalusWithRawResponse: def __init__(self, client: Dedalus) -> None: self._client = client - @cached_property - def usage(self) -> usage.UsageResourceWithRawResponse: - from .resources.usage import UsageResourceWithRawResponse - - return UsageResourceWithRawResponse(self._client.usage) - @cached_property def machines(self) -> machines.MachinesResourceWithRawResponse: from .resources.machines import MachinesResourceWithRawResponse @@ -567,12 +526,6 @@ class AsyncDedalusWithRawResponse: def __init__(self, client: AsyncDedalus) -> None: self._client = client - @cached_property - def usage(self) -> usage.AsyncUsageResourceWithRawResponse: - from .resources.usage import AsyncUsageResourceWithRawResponse - - return AsyncUsageResourceWithRawResponse(self._client.usage) - @cached_property def machines(self) -> machines.AsyncMachinesResourceWithRawResponse: from .resources.machines import AsyncMachinesResourceWithRawResponse @@ -586,12 +539,6 @@ class DedalusWithStreamedResponse: def __init__(self, client: Dedalus) -> None: self._client = client - @cached_property - def usage(self) -> usage.UsageResourceWithStreamingResponse: - from .resources.usage import UsageResourceWithStreamingResponse - - return UsageResourceWithStreamingResponse(self._client.usage) - @cached_property def machines(self) -> machines.MachinesResourceWithStreamingResponse: from .resources.machines import MachinesResourceWithStreamingResponse @@ -605,12 +552,6 @@ class AsyncDedalusWithStreamedResponse: def __init__(self, client: AsyncDedalus) -> None: self._client = client - @cached_property - def usage(self) -> usage.AsyncUsageResourceWithStreamingResponse: - from .resources.usage import AsyncUsageResourceWithStreamingResponse - - return AsyncUsageResourceWithStreamingResponse(self._client.usage) - @cached_property def machines(self) -> machines.AsyncMachinesResourceWithStreamingResponse: from .resources.machines import AsyncMachinesResourceWithStreamingResponse diff --git a/src/dedalus_sdk/_event_handler.py b/src/dedalus_sdk/_event_handler.py deleted file mode 100644 index d9a3a59..0000000 --- a/src/dedalus_sdk/_event_handler.py +++ /dev/null @@ -1,85 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import threading -from typing import Any, Callable - -EventHandler = Callable[..., Any] - - -class EventHandlerRegistry: - """Thread-safe (optional) registry of event handlers.""" - - def __init__(self, *, use_lock: bool = False) -> None: - self._handlers: dict[str, list[EventHandler]] = {} - self._once_ids: set[int] = set() - self._lock: threading.Lock | None = threading.Lock() if use_lock else None - - def _acquire(self) -> None: - if self._lock is not None: - self._lock.acquire() - - def _release(self) -> None: - if self._lock is not None: - self._lock.release() - - def add(self, event_type: str, handler: EventHandler, *, once: bool = False) -> None: - self._acquire() - try: - handlers = self._handlers.setdefault(event_type, []) - handlers.append(handler) - if once: - self._once_ids.add(id(handler)) - finally: - self._release() - - def remove(self, event_type: str, handler: EventHandler) -> None: - self._acquire() - try: - handlers = self._handlers.get(event_type) - if handlers is not None: - try: - handlers.remove(handler) - except ValueError: - pass - self._once_ids.discard(id(handler)) - finally: - self._release() - - def get_handlers(self, event_type: str) -> list[EventHandler]: - """Return a snapshot of handlers for the given event type, removing once-handlers.""" - self._acquire() - try: - handlers = self._handlers.get(event_type) - if not handlers: - return [] - result = list(handlers) - to_remove = [h for h in result if id(h) in self._once_ids] - for h in to_remove: - handlers.remove(h) - self._once_ids.discard(id(h)) - return result - finally: - self._release() - - def has_handlers(self, event_type: str) -> bool: - self._acquire() - try: - handlers = self._handlers.get(event_type) - return bool(handlers) - finally: - self._release() - - def merge_into(self, target: EventHandlerRegistry) -> None: - """Move all handlers from this registry into *target*, then clear self.""" - self._acquire() - try: - for event_type, handlers in self._handlers.items(): - for handler in handlers: - once = id(handler) in self._once_ids - target.add(event_type, handler, once=once) - self._handlers.clear() - self._once_ids.clear() - finally: - self._release() diff --git a/src/dedalus_sdk/_exceptions.py b/src/dedalus_sdk/_exceptions.py index f0c7fe2..b1b6b06 100644 --- a/src/dedalus_sdk/_exceptions.py +++ b/src/dedalus_sdk/_exceptions.py @@ -15,8 +15,6 @@ "UnprocessableEntityError", "RateLimitError", "InternalServerError", - "WebSocketConnectionClosedError", - "WebSocketQueueFullError", ] @@ -108,19 +106,3 @@ class RateLimitError(APIStatusError): class InternalServerError(APIStatusError): pass - - -class WebSocketConnectionClosedError(DedalusError): - """Raised when a WebSocket connection closes with unsent messages.""" - - unsent_messages: list[str] - - def __init__(self, message: str, *, unsent_messages: list[str]) -> None: - super().__init__(message) - self.unsent_messages = unsent_messages - - -class WebSocketQueueFullError(DedalusError): - """Raised when the outgoing WebSocket message queue exceeds its byte-size limit.""" - - pass diff --git a/src/dedalus_sdk/_send_queue.py b/src/dedalus_sdk/_send_queue.py deleted file mode 100644 index b35d0fb..0000000 --- a/src/dedalus_sdk/_send_queue.py +++ /dev/null @@ -1,90 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import typing -import threading - -from ._exceptions import WebSocketQueueFullError - - -class SendQueue: - """Bounded byte-size queue for outgoing WebSocket messages. - - Messages are stored as pre-serialized strings. The queue enforces a - maximum byte budget so that unbounded buffering cannot occur during - reconnection windows. - """ - - def __init__(self, max_bytes: int = 1_048_576) -> None: - self._queue: list[tuple[str, int]] = [] # (data, byte_length) - self._bytes: int = 0 - self._max_bytes = max_bytes - self._lock = threading.Lock() - - def enqueue(self, data: str) -> None: - """Append *data* to the queue. - - Raises :class:`WebSocketQueueFullError` if the message would - exceed the byte-size limit. - """ - byte_length = len(data.encode("utf-8")) - with self._lock: - if self._bytes + byte_length > self._max_bytes: - raise WebSocketQueueFullError("send queue is full, message discarded") - self._queue.append((data, byte_length)) - self._bytes += byte_length - - def flush_sync(self, send: typing.Callable[[str], object]) -> None: - """Send every queued message via *send*. - - If *send* raises, the failing message and all subsequent messages - are re-queued and the error is re-raised. - """ - with self._lock: - pending = list(self._queue) - self._queue.clear() - self._bytes = 0 - - for i, (data, _byte_length) in enumerate(pending): - try: - send(data) - except Exception: - with self._lock: - remaining = pending[i:] - self._queue = remaining + self._queue - self._bytes = sum(bl for _, bl in self._queue) - raise - - async def flush_async(self, send: typing.Callable[[str], typing.Awaitable[object]]) -> None: - """Async variant of :meth:`flush_sync`.""" - with self._lock: - pending = list(self._queue) - self._queue.clear() - self._bytes = 0 - - for i, (data, _byte_length) in enumerate(pending): - try: - await send(data) - except Exception: - with self._lock: - remaining = pending[i:] - self._queue = remaining + self._queue - self._bytes = sum(bl for _, bl in self._queue) - raise - - def drain(self) -> list[str]: - """Remove and return all queued messages.""" - with self._lock: - items = [data for data, _ in self._queue] - self._queue.clear() - self._bytes = 0 - return items - - def __len__(self) -> int: - with self._lock: - return len(self._queue) - - def __bool__(self) -> bool: - with self._lock: - return len(self._queue) > 0 diff --git a/src/dedalus_sdk/_streaming.py b/src/dedalus_sdk/_streaming.py index d7c0ff2..d71126c 100644 --- a/src/dedalus_sdk/_streaming.py +++ b/src/dedalus_sdk/_streaming.py @@ -59,26 +59,7 @@ def __stream__(self) -> Iterator[_T]: try: for sse in iterator: - if sse.event == "bookmark": - continue - - if sse.event == "error": - body = sse.data - - try: - body = sse.json() - err_msg = f"{body}" - except Exception: - err_msg = sse.data or f"Error code: {response.status_code}" - - raise self._client._make_status_error( - err_msg, - body=body, - response=self.response, - ) - - if sse.event == "status": - yield process_data(data=sse.json(), cast_to=cast_to, response=response) + yield process_data(data=sse.json(), cast_to=cast_to, response=response) finally: # Ensure the response is closed even if the consumer doesn't read all data response.close() @@ -144,26 +125,7 @@ async def __stream__(self) -> AsyncIterator[_T]: try: async for sse in iterator: - if sse.event == "bookmark": - continue - - if sse.event == "error": - body = sse.data - - try: - body = sse.json() - err_msg = f"{body}" - except Exception: - err_msg = sse.data or f"Error code: {response.status_code}" - - raise self._client._make_status_error( - err_msg, - body=body, - response=self.response, - ) - - if sse.event == "status": - yield process_data(data=sse.json(), cast_to=cast_to, response=response) + yield process_data(data=sse.json(), cast_to=cast_to, response=response) finally: # Ensure the response is closed even if the consumer doesn't read all data await response.aclose() diff --git a/src/dedalus_sdk/_version.py b/src/dedalus_sdk/_version.py index ff44f48..2e5e834 100644 --- a/src/dedalus_sdk/_version.py +++ b/src/dedalus_sdk/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "dedalus_sdk" -__version__ = "0.4.0" # x-release-please-version +__version__ = "0.5.0" # x-release-please-version diff --git a/src/dedalus_sdk/resources/__init__.py b/src/dedalus_sdk/resources/__init__.py index 5365a1e..2967015 100644 --- a/src/dedalus_sdk/resources/__init__.py +++ b/src/dedalus_sdk/resources/__init__.py @@ -1,13 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .usage import ( - UsageResource, - AsyncUsageResource, - UsageResourceWithRawResponse, - AsyncUsageResourceWithRawResponse, - UsageResourceWithStreamingResponse, - AsyncUsageResourceWithStreamingResponse, -) from .machines import ( MachinesResource, AsyncMachinesResource, @@ -18,12 +10,6 @@ ) __all__ = [ - "UsageResource", - "AsyncUsageResource", - "UsageResourceWithRawResponse", - "AsyncUsageResourceWithRawResponse", - "UsageResourceWithStreamingResponse", - "AsyncUsageResourceWithStreamingResponse", "MachinesResource", "AsyncMachinesResource", "MachinesResourceWithRawResponse", diff --git a/src/dedalus_sdk/resources/machines/__init__.py b/src/dedalus_sdk/resources/machines/__init__.py index 75f56d8..dfb0fcf 100644 --- a/src/dedalus_sdk/resources/machines/__init__.py +++ b/src/dedalus_sdk/resources/machines/__init__.py @@ -16,30 +16,6 @@ MachinesResourceWithStreamingResponse, AsyncMachinesResourceWithStreamingResponse, ) -from .previews import ( - PreviewsResource, - AsyncPreviewsResource, - PreviewsResourceWithRawResponse, - AsyncPreviewsResourceWithRawResponse, - PreviewsResourceWithStreamingResponse, - AsyncPreviewsResourceWithStreamingResponse, -) -from .artifacts import ( - ArtifactsResource, - AsyncArtifactsResource, - ArtifactsResourceWithRawResponse, - AsyncArtifactsResourceWithRawResponse, - ArtifactsResourceWithStreamingResponse, - AsyncArtifactsResourceWithStreamingResponse, -) -from .terminals import ( - TerminalsResource, - AsyncTerminalsResource, - TerminalsResourceWithRawResponse, - AsyncTerminalsResourceWithRawResponse, - TerminalsResourceWithStreamingResponse, - AsyncTerminalsResourceWithStreamingResponse, -) from .executions import ( ExecutionsResource, AsyncExecutionsResource, @@ -50,18 +26,6 @@ ) __all__ = [ - "ArtifactsResource", - "AsyncArtifactsResource", - "ArtifactsResourceWithRawResponse", - "AsyncArtifactsResourceWithRawResponse", - "ArtifactsResourceWithStreamingResponse", - "AsyncArtifactsResourceWithStreamingResponse", - "PreviewsResource", - "AsyncPreviewsResource", - "PreviewsResourceWithRawResponse", - "AsyncPreviewsResourceWithRawResponse", - "PreviewsResourceWithStreamingResponse", - "AsyncPreviewsResourceWithStreamingResponse", "SSHResource", "AsyncSSHResource", "SSHResourceWithRawResponse", @@ -74,12 +38,6 @@ "AsyncExecutionsResourceWithRawResponse", "ExecutionsResourceWithStreamingResponse", "AsyncExecutionsResourceWithStreamingResponse", - "TerminalsResource", - "AsyncTerminalsResource", - "TerminalsResourceWithRawResponse", - "AsyncTerminalsResourceWithRawResponse", - "TerminalsResourceWithStreamingResponse", - "AsyncTerminalsResourceWithStreamingResponse", "MachinesResource", "AsyncMachinesResource", "MachinesResourceWithRawResponse", diff --git a/src/dedalus_sdk/resources/machines/artifacts.py b/src/dedalus_sdk/resources/machines/artifacts.py deleted file mode 100644 index 8856407..0000000 --- a/src/dedalus_sdk/resources/machines/artifacts.py +++ /dev/null @@ -1,382 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import path_template, 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 ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.machines import artifact_list_params -from ...types.machines.artifact import Artifact - -__all__ = ["ArtifactsResource", "AsyncArtifactsResource"] - - -class ArtifactsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ArtifactsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return ArtifactsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ArtifactsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return ArtifactsResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - machine_id: str, - artifact_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, - ) -> Artifact: - """ - Get artifact - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not artifact_id: - raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") - return self._get( - path_template( - "/v1/machines/{machine_id}/artifacts/{artifact_id}", machine_id=machine_id, artifact_id=artifact_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Artifact, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> SyncCursorPage[Artifact]: - """ - List artifacts - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/artifacts", machine_id=machine_id), - page=SyncCursorPage[Artifact], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - artifact_list_params.ArtifactListParams, - ), - ), - model=Artifact, - ) - - def delete( - self, - *, - machine_id: str, - artifact_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, - idempotency_key: str | None = None, - ) -> Artifact: - """ - Delete artifact - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not artifact_id: - raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") - return self._delete( - path_template( - "/v1/machines/{machine_id}/artifacts/{artifact_id}", machine_id=machine_id, artifact_id=artifact_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Artifact, - ) - - -class AsyncArtifactsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncArtifactsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return AsyncArtifactsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncArtifactsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return AsyncArtifactsResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - machine_id: str, - artifact_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, - ) -> Artifact: - """ - Get artifact - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not artifact_id: - raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") - return await self._get( - path_template( - "/v1/machines/{machine_id}/artifacts/{artifact_id}", machine_id=machine_id, artifact_id=artifact_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Artifact, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> AsyncPaginator[Artifact, AsyncCursorPage[Artifact]]: - """ - List artifacts - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/artifacts", machine_id=machine_id), - page=AsyncCursorPage[Artifact], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - artifact_list_params.ArtifactListParams, - ), - ), - model=Artifact, - ) - - async def delete( - self, - *, - machine_id: str, - artifact_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, - idempotency_key: str | None = None, - ) -> Artifact: - """ - Delete artifact - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not artifact_id: - raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") - return await self._delete( - path_template( - "/v1/machines/{machine_id}/artifacts/{artifact_id}", machine_id=machine_id, artifact_id=artifact_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Artifact, - ) - - -class ArtifactsResourceWithRawResponse: - def __init__(self, artifacts: ArtifactsResource) -> None: - self._artifacts = artifacts - - self.retrieve = to_raw_response_wrapper( - artifacts.retrieve, - ) - self.list = to_raw_response_wrapper( - artifacts.list, - ) - self.delete = to_raw_response_wrapper( - artifacts.delete, - ) - - -class AsyncArtifactsResourceWithRawResponse: - def __init__(self, artifacts: AsyncArtifactsResource) -> None: - self._artifacts = artifacts - - self.retrieve = async_to_raw_response_wrapper( - artifacts.retrieve, - ) - self.list = async_to_raw_response_wrapper( - artifacts.list, - ) - self.delete = async_to_raw_response_wrapper( - artifacts.delete, - ) - - -class ArtifactsResourceWithStreamingResponse: - def __init__(self, artifacts: ArtifactsResource) -> None: - self._artifacts = artifacts - - self.retrieve = to_streamed_response_wrapper( - artifacts.retrieve, - ) - self.list = to_streamed_response_wrapper( - artifacts.list, - ) - self.delete = to_streamed_response_wrapper( - artifacts.delete, - ) - - -class AsyncArtifactsResourceWithStreamingResponse: - def __init__(self, artifacts: AsyncArtifactsResource) -> None: - self._artifacts = artifacts - - self.retrieve = async_to_streamed_response_wrapper( - artifacts.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - artifacts.list, - ) - self.delete = async_to_streamed_response_wrapper( - artifacts.delete, - ) diff --git a/src/dedalus_sdk/resources/machines/machines.py b/src/dedalus_sdk/resources/machines/machines.py index b78a9ca..3971492 100644 --- a/src/dedalus_sdk/resources/machines/machines.py +++ b/src/dedalus_sdk/resources/machines/machines.py @@ -14,32 +14,8 @@ ) from ...types import machine_list_params, machine_create_params, machine_update_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 .previews import ( - PreviewsResource, - AsyncPreviewsResource, - PreviewsResourceWithRawResponse, - AsyncPreviewsResourceWithRawResponse, - PreviewsResourceWithStreamingResponse, - AsyncPreviewsResourceWithStreamingResponse, -) +from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property -from .artifacts import ( - ArtifactsResource, - AsyncArtifactsResource, - ArtifactsResourceWithRawResponse, - AsyncArtifactsResourceWithRawResponse, - ArtifactsResourceWithStreamingResponse, - AsyncArtifactsResourceWithStreamingResponse, -) -from .terminals import ( - TerminalsResource, - AsyncTerminalsResource, - TerminalsResourceWithRawResponse, - AsyncTerminalsResourceWithRawResponse, - TerminalsResourceWithStreamingResponse, - AsyncTerminalsResourceWithStreamingResponse, -) from .executions import ( ExecutionsResource, AsyncExecutionsResource, @@ -55,24 +31,16 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ..._streaming import Stream, AsyncStream from ...pagination import SyncCursorPage, AsyncCursorPage from ..._base_client import AsyncPaginator, make_request_options from ...types.machine import Machine from ...types.machine_list_item import MachineListItem +from ...types.machine_retrieve_response import MachineRetrieveResponse __all__ = ["MachinesResource", "AsyncMachinesResource"] class MachinesResource(SyncAPIResource): - @cached_property - def artifacts(self) -> ArtifactsResource: - return ArtifactsResource(self._client) - - @cached_property - def previews(self) -> PreviewsResource: - return PreviewsResource(self._client) - @cached_property def ssh(self) -> SSHResource: return SSHResource(self._client) @@ -81,10 +49,6 @@ def ssh(self) -> SSHResource: def executions(self) -> ExecutionsResource: return ExecutionsResource(self._client) - @cached_property - def terminals(self) -> TerminalsResource: - return TerminalsResource(self._client) - @cached_property def with_raw_response(self) -> MachinesResourceWithRawResponse: """ @@ -107,10 +71,10 @@ def with_streaming_response(self) -> MachinesResourceWithStreamingResponse: def create( self, *, - memory_mib: int, - storage_gib: int, - vcpu: float, autosleep: str | Omit = omit, + memory_mib: int | Omit = omit, + storage_gib: int | Omit = omit, + vcpu: float | 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, @@ -119,19 +83,20 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Machine: - """ - Create machine + """Create machine Args: + autosleep: Idle window before autosleep. + + Accepts fixed duration units like 30s, 30m, 2h, + 7d3h4s, or 1w3d, raw seconds ("1800"), or never to disable. + memory_mib: Memory in MiB. storage_gib: Storage in GiB. vcpu: CPU in vCPUs. - autosleep: Idle window before autosleep. Accepts fixed duration units like 30s, 30m, 2h, - 7d3h4s, or 1w3d, raw seconds ("1800"), or never to disable. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -146,10 +111,10 @@ def create( "/v1/machines", body=maybe_transform( { + "autosleep": autosleep, "memory_mib": memory_mib, "storage_gib": storage_gib, "vcpu": vcpu, - "autosleep": autosleep, }, machine_create_params.MachineCreateParams, ), @@ -173,7 +138,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Machine: + ) -> MachineRetrieveResponse: """ Get machine @@ -193,7 +158,7 @@ def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Machine, + cast_to=MachineRetrieveResponse, ) def update( @@ -422,57 +387,8 @@ def wake( cast_to=Machine, ) - def watch( - self, - *, - machine_id: str, - last_event_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, - ) -> Stream[Machine]: - """Streams machine lifecycle updates over Server-Sent Events. - - Each `status` event - contains a full `LifecycleResponse` payload. The stream closes after the machine - reaches its current desired 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} - extra_headers = {**strip_not_given({"Last-Event-ID": last_event_id}), **(extra_headers or {})} - return self._get( - path_template("/v1/machines/{machine_id}/status/stream", machine_id=machine_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Machine, - stream=True, - stream_cls=Stream[Machine], - ) - class AsyncMachinesResource(AsyncAPIResource): - @cached_property - def artifacts(self) -> AsyncArtifactsResource: - return AsyncArtifactsResource(self._client) - - @cached_property - def previews(self) -> AsyncPreviewsResource: - return AsyncPreviewsResource(self._client) - @cached_property def ssh(self) -> AsyncSSHResource: return AsyncSSHResource(self._client) @@ -481,10 +397,6 @@ def ssh(self) -> AsyncSSHResource: def executions(self) -> AsyncExecutionsResource: return AsyncExecutionsResource(self._client) - @cached_property - def terminals(self) -> AsyncTerminalsResource: - return AsyncTerminalsResource(self._client) - @cached_property def with_raw_response(self) -> AsyncMachinesResourceWithRawResponse: """ @@ -507,10 +419,10 @@ def with_streaming_response(self) -> AsyncMachinesResourceWithStreamingResponse: async def create( self, *, - memory_mib: int, - storage_gib: int, - vcpu: float, autosleep: str | Omit = omit, + memory_mib: int | Omit = omit, + storage_gib: int | Omit = omit, + vcpu: float | 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, @@ -519,19 +431,20 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = not_given, idempotency_key: str | None = None, ) -> Machine: - """ - Create machine + """Create machine Args: + autosleep: Idle window before autosleep. + + Accepts fixed duration units like 30s, 30m, 2h, + 7d3h4s, or 1w3d, raw seconds ("1800"), or never to disable. + memory_mib: Memory in MiB. storage_gib: Storage in GiB. vcpu: CPU in vCPUs. - autosleep: Idle window before autosleep. Accepts fixed duration units like 30s, 30m, 2h, - 7d3h4s, or 1w3d, raw seconds ("1800"), or never to disable. - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -546,10 +459,10 @@ async def create( "/v1/machines", body=await async_maybe_transform( { + "autosleep": autosleep, "memory_mib": memory_mib, "storage_gib": storage_gib, "vcpu": vcpu, - "autosleep": autosleep, }, machine_create_params.MachineCreateParams, ), @@ -573,7 +486,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Machine: + ) -> MachineRetrieveResponse: """ Get machine @@ -593,7 +506,7 @@ async def retrieve( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=Machine, + cast_to=MachineRetrieveResponse, ) async def update( @@ -822,47 +735,6 @@ async def wake( cast_to=Machine, ) - async def watch( - self, - *, - machine_id: str, - last_event_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, - ) -> AsyncStream[Machine]: - """Streams machine lifecycle updates over Server-Sent Events. - - Each `status` event - contains a full `LifecycleResponse` payload. The stream closes after the machine - reaches its current desired 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})} - extra_headers = {**strip_not_given({"Last-Event-ID": last_event_id}), **(extra_headers or {})} - return await self._get( - path_template("/v1/machines/{machine_id}/status/stream", machine_id=machine_id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Machine, - stream=True, - stream_cls=AsyncStream[Machine], - ) - class MachinesResourceWithRawResponse: def __init__(self, machines: MachinesResource) -> None: @@ -889,17 +761,6 @@ def __init__(self, machines: MachinesResource) -> None: self.wake = to_raw_response_wrapper( machines.wake, ) - self.watch = to_raw_response_wrapper( - machines.watch, - ) - - @cached_property - def artifacts(self) -> ArtifactsResourceWithRawResponse: - return ArtifactsResourceWithRawResponse(self._machines.artifacts) - - @cached_property - def previews(self) -> PreviewsResourceWithRawResponse: - return PreviewsResourceWithRawResponse(self._machines.previews) @cached_property def ssh(self) -> SSHResourceWithRawResponse: @@ -909,10 +770,6 @@ def ssh(self) -> SSHResourceWithRawResponse: def executions(self) -> ExecutionsResourceWithRawResponse: return ExecutionsResourceWithRawResponse(self._machines.executions) - @cached_property - def terminals(self) -> TerminalsResourceWithRawResponse: - return TerminalsResourceWithRawResponse(self._machines.terminals) - class AsyncMachinesResourceWithRawResponse: def __init__(self, machines: AsyncMachinesResource) -> None: @@ -939,17 +796,6 @@ def __init__(self, machines: AsyncMachinesResource) -> None: self.wake = async_to_raw_response_wrapper( machines.wake, ) - self.watch = async_to_raw_response_wrapper( - machines.watch, - ) - - @cached_property - def artifacts(self) -> AsyncArtifactsResourceWithRawResponse: - return AsyncArtifactsResourceWithRawResponse(self._machines.artifacts) - - @cached_property - def previews(self) -> AsyncPreviewsResourceWithRawResponse: - return AsyncPreviewsResourceWithRawResponse(self._machines.previews) @cached_property def ssh(self) -> AsyncSSHResourceWithRawResponse: @@ -959,10 +805,6 @@ def ssh(self) -> AsyncSSHResourceWithRawResponse: def executions(self) -> AsyncExecutionsResourceWithRawResponse: return AsyncExecutionsResourceWithRawResponse(self._machines.executions) - @cached_property - def terminals(self) -> AsyncTerminalsResourceWithRawResponse: - return AsyncTerminalsResourceWithRawResponse(self._machines.terminals) - class MachinesResourceWithStreamingResponse: def __init__(self, machines: MachinesResource) -> None: @@ -989,17 +831,6 @@ def __init__(self, machines: MachinesResource) -> None: self.wake = to_streamed_response_wrapper( machines.wake, ) - self.watch = to_streamed_response_wrapper( - machines.watch, - ) - - @cached_property - def artifacts(self) -> ArtifactsResourceWithStreamingResponse: - return ArtifactsResourceWithStreamingResponse(self._machines.artifacts) - - @cached_property - def previews(self) -> PreviewsResourceWithStreamingResponse: - return PreviewsResourceWithStreamingResponse(self._machines.previews) @cached_property def ssh(self) -> SSHResourceWithStreamingResponse: @@ -1009,10 +840,6 @@ def ssh(self) -> SSHResourceWithStreamingResponse: def executions(self) -> ExecutionsResourceWithStreamingResponse: return ExecutionsResourceWithStreamingResponse(self._machines.executions) - @cached_property - def terminals(self) -> TerminalsResourceWithStreamingResponse: - return TerminalsResourceWithStreamingResponse(self._machines.terminals) - class AsyncMachinesResourceWithStreamingResponse: def __init__(self, machines: AsyncMachinesResource) -> None: @@ -1039,17 +866,6 @@ def __init__(self, machines: AsyncMachinesResource) -> None: self.wake = async_to_streamed_response_wrapper( machines.wake, ) - self.watch = async_to_streamed_response_wrapper( - machines.watch, - ) - - @cached_property - def artifacts(self) -> AsyncArtifactsResourceWithStreamingResponse: - return AsyncArtifactsResourceWithStreamingResponse(self._machines.artifacts) - - @cached_property - def previews(self) -> AsyncPreviewsResourceWithStreamingResponse: - return AsyncPreviewsResourceWithStreamingResponse(self._machines.previews) @cached_property def ssh(self) -> AsyncSSHResourceWithStreamingResponse: @@ -1058,7 +874,3 @@ def ssh(self) -> AsyncSSHResourceWithStreamingResponse: @cached_property def executions(self) -> AsyncExecutionsResourceWithStreamingResponse: return AsyncExecutionsResourceWithStreamingResponse(self._machines.executions) - - @cached_property - def terminals(self) -> AsyncTerminalsResourceWithStreamingResponse: - return AsyncTerminalsResourceWithStreamingResponse(self._machines.terminals) diff --git a/src/dedalus_sdk/resources/machines/previews.py b/src/dedalus_sdk/resources/machines/previews.py deleted file mode 100644 index 074ef9b..0000000 --- a/src/dedalus_sdk/resources/machines/previews.py +++ /dev/null @@ -1,498 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import 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 ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.machines import preview_list_params, preview_create_params -from ...types.machines.preview import Preview - -__all__ = ["PreviewsResource", "AsyncPreviewsResource"] - - -class PreviewsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PreviewsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return PreviewsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PreviewsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return PreviewsResourceWithStreamingResponse(self) - - def create( - self, - *, - machine_id: str, - port: int, - protocol: Literal["http", "https"] | Omit = omit, - visibility: Literal["public", "private", "org"] | 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, - idempotency_key: str | None = None, - ) -> Preview: - """ - Create preview - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._post( - path_template("/v1/machines/{machine_id}/previews", machine_id=machine_id), - body=maybe_transform( - { - "port": port, - "protocol": protocol, - "visibility": visibility, - }, - preview_create_params.PreviewCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Preview, - ) - - def retrieve( - self, - *, - machine_id: str, - preview_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, - ) -> Preview: - """ - Get preview - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not preview_id: - raise ValueError(f"Expected a non-empty value for `preview_id` but received {preview_id!r}") - return self._get( - path_template( - "/v1/machines/{machine_id}/previews/{preview_id}", machine_id=machine_id, preview_id=preview_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Preview, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> SyncCursorPage[Preview]: - """ - List previews - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/previews", machine_id=machine_id), - page=SyncCursorPage[Preview], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - preview_list_params.PreviewListParams, - ), - ), - model=Preview, - ) - - def delete( - self, - *, - machine_id: str, - preview_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, - idempotency_key: str | None = None, - ) -> Preview: - """ - Delete preview - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not preview_id: - raise ValueError(f"Expected a non-empty value for `preview_id` but received {preview_id!r}") - return self._delete( - path_template( - "/v1/machines/{machine_id}/previews/{preview_id}", machine_id=machine_id, preview_id=preview_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Preview, - ) - - -class AsyncPreviewsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPreviewsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return AsyncPreviewsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPreviewsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return AsyncPreviewsResourceWithStreamingResponse(self) - - async def create( - self, - *, - machine_id: str, - port: int, - protocol: Literal["http", "https"] | Omit = omit, - visibility: Literal["public", "private", "org"] | 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, - idempotency_key: str | None = None, - ) -> Preview: - """ - Create preview - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return await self._post( - path_template("/v1/machines/{machine_id}/previews", machine_id=machine_id), - body=await async_maybe_transform( - { - "port": port, - "protocol": protocol, - "visibility": visibility, - }, - preview_create_params.PreviewCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Preview, - ) - - async def retrieve( - self, - *, - machine_id: str, - preview_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, - ) -> Preview: - """ - Get preview - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not preview_id: - raise ValueError(f"Expected a non-empty value for `preview_id` but received {preview_id!r}") - return await self._get( - path_template( - "/v1/machines/{machine_id}/previews/{preview_id}", machine_id=machine_id, preview_id=preview_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Preview, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> AsyncPaginator[Preview, AsyncCursorPage[Preview]]: - """ - List previews - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/previews", machine_id=machine_id), - page=AsyncCursorPage[Preview], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - preview_list_params.PreviewListParams, - ), - ), - model=Preview, - ) - - async def delete( - self, - *, - machine_id: str, - preview_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, - idempotency_key: str | None = None, - ) -> Preview: - """ - Delete preview - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not preview_id: - raise ValueError(f"Expected a non-empty value for `preview_id` but received {preview_id!r}") - return await self._delete( - path_template( - "/v1/machines/{machine_id}/previews/{preview_id}", machine_id=machine_id, preview_id=preview_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Preview, - ) - - -class PreviewsResourceWithRawResponse: - def __init__(self, previews: PreviewsResource) -> None: - self._previews = previews - - self.create = to_raw_response_wrapper( - previews.create, - ) - self.retrieve = to_raw_response_wrapper( - previews.retrieve, - ) - self.list = to_raw_response_wrapper( - previews.list, - ) - self.delete = to_raw_response_wrapper( - previews.delete, - ) - - -class AsyncPreviewsResourceWithRawResponse: - def __init__(self, previews: AsyncPreviewsResource) -> None: - self._previews = previews - - self.create = async_to_raw_response_wrapper( - previews.create, - ) - self.retrieve = async_to_raw_response_wrapper( - previews.retrieve, - ) - self.list = async_to_raw_response_wrapper( - previews.list, - ) - self.delete = async_to_raw_response_wrapper( - previews.delete, - ) - - -class PreviewsResourceWithStreamingResponse: - def __init__(self, previews: PreviewsResource) -> None: - self._previews = previews - - self.create = to_streamed_response_wrapper( - previews.create, - ) - self.retrieve = to_streamed_response_wrapper( - previews.retrieve, - ) - self.list = to_streamed_response_wrapper( - previews.list, - ) - self.delete = to_streamed_response_wrapper( - previews.delete, - ) - - -class AsyncPreviewsResourceWithStreamingResponse: - def __init__(self, previews: AsyncPreviewsResource) -> None: - self._previews = previews - - self.create = async_to_streamed_response_wrapper( - previews.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - previews.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - previews.list, - ) - self.delete = async_to_streamed_response_wrapper( - previews.delete, - ) diff --git a/src/dedalus_sdk/resources/machines/terminals.py b/src/dedalus_sdk/resources/machines/terminals.py deleted file mode 100644 index 5ffeb03..0000000 --- a/src/dedalus_sdk/resources/machines/terminals.py +++ /dev/null @@ -1,1503 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import json -import time -import random -import logging -from types import TracebackType -from typing import TYPE_CHECKING, Any, Dict, Union, Callable, Iterator, Awaitable, cast -from typing_extensions import AsyncIterator - -import httpx -from pydantic import BaseModel - -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 ..._models import construct_type_unchecked -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 ...pagination import SyncCursorPage, AsyncCursorPage -from ..._exceptions import DedalusError, WebSocketConnectionClosedError -from ..._send_queue import SendQueue -from ..._base_client import AsyncPaginator, _merge_mappings, make_request_options -from ..._event_handler import EventHandlerRegistry -from ...types.machines import terminal_list_params, terminal_create_params -from ...types.machines.terminal import Terminal -from ...types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides, is_recoverable_close -from ...types.websocket_connection_options import WebSocketConnectionOptions -from ...types.machines.terminal_error_event import TerminalErrorEvent -from ...types.machines.terminal_client_event import TerminalClientEvent -from ...types.machines.terminal_server_event import TerminalServerEvent -from ...types.machines.terminal_client_event_param import TerminalClientEventParam - -if TYPE_CHECKING: - from websockets.sync.client import ClientConnection as WebSocketConnection - from websockets.asyncio.client import ClientConnection as AsyncWebSocketConnection - - from ..._client import Dedalus, AsyncDedalus - -__all__ = ["TerminalsResource", "AsyncTerminalsResource"] - -log: logging.Logger = logging.getLogger(__name__) - - -class TerminalsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> TerminalsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return TerminalsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> TerminalsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return TerminalsResourceWithStreamingResponse(self) - - def create( - self, - *, - machine_id: str, - height: int, - width: int, - cwd: str | Omit = omit, - env: Dict[str, str] | Omit = omit, - shell: 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, - idempotency_key: str | None = None, - ) -> Terminal: - """ - Create terminal - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._post( - path_template("/v1/machines/{machine_id}/terminals", machine_id=machine_id), - body=maybe_transform( - { - "height": height, - "width": width, - "cwd": cwd, - "env": env, - "shell": shell, - }, - terminal_create_params.TerminalCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Terminal, - ) - - def retrieve( - self, - *, - machine_id: str, - terminal_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, - ) -> Terminal: - """ - Get terminal - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {terminal_id!r}") - return self._get( - path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}", machine_id=machine_id, terminal_id=terminal_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Terminal, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> SyncCursorPage[Terminal]: - """ - List terminals - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/terminals", machine_id=machine_id), - page=SyncCursorPage[Terminal], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - terminal_list_params.TerminalListParams, - ), - ), - model=Terminal, - ) - - def delete( - self, - *, - machine_id: str, - terminal_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, - idempotency_key: str | None = None, - ) -> Terminal: - """ - Delete terminal - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {terminal_id!r}") - return self._delete( - path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}", machine_id=machine_id, terminal_id=terminal_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Terminal, - ) - - def connect( - self, - *, - machine_id: str, - terminal_id: str, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebSocketConnectionOptions = {}, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - max_queue_size: int = 1_048_576, - ) -> TerminalsResourceConnectionManager: - return TerminalsResourceConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - on_reconnecting=on_reconnecting, - max_retries=max_retries, - initial_delay=initial_delay, - max_delay=max_delay, - max_queue_size=max_queue_size, - machine_id=machine_id, - terminal_id=terminal_id, - ) - - -class AsyncTerminalsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncTerminalsResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return AsyncTerminalsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncTerminalsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return AsyncTerminalsResourceWithStreamingResponse(self) - - async def create( - self, - *, - machine_id: str, - height: int, - width: int, - cwd: str | Omit = omit, - env: Dict[str, str] | Omit = omit, - shell: 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, - idempotency_key: str | None = None, - ) -> Terminal: - """ - Create terminal - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return await self._post( - path_template("/v1/machines/{machine_id}/terminals", machine_id=machine_id), - body=await async_maybe_transform( - { - "height": height, - "width": width, - "cwd": cwd, - "env": env, - "shell": shell, - }, - terminal_create_params.TerminalCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Terminal, - ) - - async def retrieve( - self, - *, - machine_id: str, - terminal_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, - ) -> Terminal: - """ - Get terminal - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {terminal_id!r}") - return await self._get( - path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}", machine_id=machine_id, terminal_id=terminal_id - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Terminal, - ) - - def list( - self, - *, - machine_id: str, - cursor: str | Omit = omit, - limit: 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, - ) -> AsyncPaginator[Terminal, AsyncCursorPage[Terminal]]: - """ - List terminals - - 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 machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - return self._get_api_list( - path_template("/v1/machines/{machine_id}/terminals", machine_id=machine_id), - page=AsyncCursorPage[Terminal], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "cursor": cursor, - "limit": limit, - }, - terminal_list_params.TerminalListParams, - ), - ), - model=Terminal, - ) - - async def delete( - self, - *, - machine_id: str, - terminal_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, - idempotency_key: str | None = None, - ) -> Terminal: - """ - Delete terminal - - 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 - - idempotency_key: Specify a custom idempotency key for this request - """ - if not machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {machine_id!r}") - if not terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {terminal_id!r}") - return await self._delete( - path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}", machine_id=machine_id, terminal_id=terminal_id - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - idempotency_key=idempotency_key, - ), - cast_to=Terminal, - ) - - def connect( - self, - *, - machine_id: str, - terminal_id: str, - extra_query: Query = {}, - extra_headers: Headers = {}, - websocket_connection_options: WebSocketConnectionOptions = {}, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - max_queue_size: int = 1_048_576, - ) -> AsyncTerminalsResourceConnectionManager: - return AsyncTerminalsResourceConnectionManager( - client=self._client, - extra_query=extra_query, - extra_headers=extra_headers, - websocket_connection_options=websocket_connection_options, - on_reconnecting=on_reconnecting, - max_retries=max_retries, - initial_delay=initial_delay, - max_delay=max_delay, - max_queue_size=max_queue_size, - machine_id=machine_id, - terminal_id=terminal_id, - ) - - -class TerminalsResourceWithRawResponse: - def __init__(self, terminals: TerminalsResource) -> None: - self._terminals = terminals - - self.create = to_raw_response_wrapper( - terminals.create, - ) - self.retrieve = to_raw_response_wrapper( - terminals.retrieve, - ) - self.list = to_raw_response_wrapper( - terminals.list, - ) - self.delete = to_raw_response_wrapper( - terminals.delete, - ) - - -class AsyncTerminalsResourceWithRawResponse: - def __init__(self, terminals: AsyncTerminalsResource) -> None: - self._terminals = terminals - - self.create = async_to_raw_response_wrapper( - terminals.create, - ) - self.retrieve = async_to_raw_response_wrapper( - terminals.retrieve, - ) - self.list = async_to_raw_response_wrapper( - terminals.list, - ) - self.delete = async_to_raw_response_wrapper( - terminals.delete, - ) - - -class TerminalsResourceWithStreamingResponse: - def __init__(self, terminals: TerminalsResource) -> None: - self._terminals = terminals - - self.create = to_streamed_response_wrapper( - terminals.create, - ) - self.retrieve = to_streamed_response_wrapper( - terminals.retrieve, - ) - self.list = to_streamed_response_wrapper( - terminals.list, - ) - self.delete = to_streamed_response_wrapper( - terminals.delete, - ) - - -class AsyncTerminalsResourceWithStreamingResponse: - def __init__(self, terminals: AsyncTerminalsResource) -> None: - self._terminals = terminals - - self.create = async_to_streamed_response_wrapper( - terminals.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - terminals.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - terminals.list, - ) - self.delete = async_to_streamed_response_wrapper( - terminals.delete, - ) - - -class AsyncTerminalsResourceConnection: - """Represents a live WebSocket connection to the Terminals API""" - - _connection: AsyncWebSocketConnection - - def __init__( - self, - connection: AsyncWebSocketConnection, - *, - make_ws: Callable[[Query, Headers], Awaitable[AsyncWebSocketConnection]] | None = None, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - extra_query: Query = {}, - extra_headers: Headers = {}, - send_queue: SendQueue | None = None, - ) -> None: - self._connection = connection - self._make_ws = make_ws - self._on_reconnecting = on_reconnecting - self._max_retries = max_retries - self._initial_delay = initial_delay - self._max_delay = max_delay - self._extra_query = extra_query - self._extra_headers = extra_headers - self._intentionally_closed = False - self._is_reconnecting = False - self._send_queue = send_queue or SendQueue() - self._event_handler_registry = EventHandlerRegistry(use_lock=False) - - async def __aiter__(self) -> AsyncIterator[TerminalServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - - while True: - try: - yield await self.recv() - except ConnectionClosedOK: - return - except ConnectionClosedError as exc: - if not await self._reconnect(exc): - unsent = self._send_queue.drain() - if unsent: - raise WebSocketConnectionClosedError( - "WebSocket connection closed with unsent messages", - unsent_messages=unsent, - ) from exc - raise - - async def recv(self) -> TerminalServerEvent: - """ - Receive the next message from the connection and parses it into a `TerminalServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(await self.recv_bytes()) - - async def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `TerminalServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = await self._connection.recv(decode=False) - log.debug(f"Received WebSocket message: %s", message) - return message - - async def send(self, event: TerminalClientEvent | TerminalClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(await async_maybe_transform(event, TerminalClientEventParam)) - ) - if self._is_reconnecting: - self._send_queue.enqueue(data) - return - try: - await self._connection.send(data) - except Exception: - self._send_queue.enqueue(data) - raise - - async def send_raw(self, data: bytes | str) -> None: - if self._is_reconnecting: - raw = data if isinstance(data, str) else data.decode("utf-8") - self._send_queue.enqueue(raw) - return - await self._connection.send(data) - - async def close(self, *, code: int = 1000, reason: str = "") -> None: - self._intentionally_closed = True - await self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> TerminalServerEvent: - """ - Converts a raw `str` or `bytes` message into a `TerminalServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - TerminalServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, TerminalServerEvent)) - ) - - async def _reconnect(self, exc: Exception) -> bool: - """Attempt to reconnect after a connection failure. - - Returns ``True`` if a new connection was established, ``False`` if the - caller should re-raise the original exception. - """ - import asyncio - - if self._on_reconnecting is None or self._make_ws is None: - return False - - from websockets.exceptions import ConnectionClosedError - - close_code = 1006 - if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: - close_code = exc.rcvd.code - - if not is_recoverable_close(close_code): - return False - - self._is_reconnecting = True - - for attempt in range(1, self._max_retries + 1): - base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) - jitter = 0.75 + random.random() * 0.25 - delay = base_delay * jitter - - event = ReconnectingEvent( - attempt=attempt, - max_attempts=self._max_retries, - delay=delay, - close_code=close_code, - extra_query=self._extra_query, - extra_headers=self._extra_headers, - ) - - try: - result = self._on_reconnecting(event) - except Exception: - self._is_reconnecting = False - return False - - if result is not None and result.get("abort"): - self._is_reconnecting = False - return False - - if result is not None: - if "extra_query" in result: - self._extra_query = result["extra_query"] - if "extra_headers" in result: - self._extra_headers = result["extra_headers"] - - log.info( - "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", - attempt, - self._max_retries, - delay, - ) - await asyncio.sleep(delay) - - if self._intentionally_closed: - self._is_reconnecting = False - return False - - try: - self._connection = await self._make_ws(self._extra_query, self._extra_headers) - log.info("Reconnected to WebSocket API") - self._is_reconnecting = False - await self._flush_send_queue() - return True - except Exception: - pass - - self._is_reconnecting = False - return False - - async def _flush_send_queue(self) -> None: - """Send all queued messages over the current connection.""" - - async def _send(data: str) -> None: - await self._connection.send(data) - - try: - await self._send_queue.flush_async(_send) - except Exception: - log.warning("Failed to flush send queue after reconnect", exc_info=True) - - def on( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[AsyncTerminalsResourceConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Adds the handler to the end of the handlers list for the given event type. - - No checks are made to see if the handler has already been added. Multiple calls - passing the same combination of event type and handler will result in the handler - being added, and called, multiple times. - - Can be used as a method (returns ``self`` for chaining):: - - connection.on("output", my_handler) - - Or as a decorator:: - - @connection.on("output") - async def my_handler(event): ... - """ - if handler is not None: - self._event_handler_registry.add(event_type, handler) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self._event_handler_registry.add(event_type, fn) - return fn - - return decorator - - def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncTerminalsResourceConnection: - """Remove a previously registered event handler.""" - self._event_handler_registry.remove(event_type, handler) - return self - - def once( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[AsyncTerminalsResourceConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register a one-time event handler. - - Automatically removed after first invocation. - """ - if handler is not None: - self._event_handler_registry.add(event_type, handler, once=True) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self._event_handler_registry.add(event_type, fn, once=True) - return fn - - return decorator - - async def dispatch_events(self) -> None: - """Run the event loop, dispatching received events to registered handlers. - - Blocks until the connection is closed. This is the push-based - alternative to iterating with ``async for event in connection``. - - If an ``"error"`` event arrives and no handler is registered for - ``"error"`` or ``"event"``, an ``DedalusError`` is raised. - """ - import asyncio - - async for event in self: - event_type = event.type - specific = self._event_handler_registry.get_handlers(event_type) - generic = self._event_handler_registry.get_handlers("event") - - if event_type == "error" and not specific and not generic: - if isinstance(event, TerminalErrorEvent): - raise DedalusError(f"WebSocket error: {event}") - - for handler in specific: - result = handler(event) - if asyncio.iscoroutine(result): - await result - - for handler in generic: - result = handler(event) - if asyncio.iscoroutine(result): - await result - - -class AsyncTerminalsResourceConnectionManager: - """ - Context manager over a `AsyncTerminalsResourceConnection` that is returned by `machines.terminals.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.machines.terminals.connect(...).enter() - # ... - await connection.close() - ``` - """ - - def __init__( - self, - *, - client: AsyncDedalus, - machine_id: str, - terminal_id: str, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebSocketConnectionOptions, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - max_queue_size: int = 1_048_576, - ) -> None: - self.__client = client - self.__machine_id = machine_id - self.__terminal_id = terminal_id - self.__connection: AsyncTerminalsResourceConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - self.__on_reconnecting = on_reconnecting - self.__max_retries = max_retries - self.__initial_delay = initial_delay - self.__max_delay = max_delay - self.__send_queue = SendQueue(max_bytes=max_queue_size) - self.__event_handler_registry = EventHandlerRegistry(use_lock=False) - - def send(self, event: TerminalClientEvent | TerminalClientEventParam) -> None: - """Queue a message to be sent when the connection is established. - - This can be called before entering the context manager. Queued messages - are automatically sent once the WebSocket connection opens. - """ - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(event) - ) - self.__send_queue.enqueue(data) - - def on( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[AsyncTerminalsResourceConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register an event handler before the connection is established. - - Handlers are transferred to the connection on enter. Supports the - same method and decorator forms as ``AsyncTerminalsResourceConnection.on``. - """ - if handler is not None: - self.__event_handler_registry.add(event_type, handler) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self.__event_handler_registry.add(event_type, fn) - return fn - - return decorator - - def off(self, event_type: str, handler: Callable[..., Any]) -> AsyncTerminalsResourceConnectionManager: - """Remove a previously registered event handler.""" - self.__event_handler_registry.remove(event_type, handler) - return self - - def once( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[AsyncTerminalsResourceConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register a one-time event handler before the connection is established.""" - if handler is not None: - self.__event_handler_registry.add(event_type, handler, once=True) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self.__event_handler_registry.add(event_type, fn, once=True) - return fn - - return decorator - - async def __aenter__(self) -> AsyncTerminalsResourceConnection: - """ - If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = await client.machines.terminals.connect(...).enter() - # ... - await connection.close() - ``` - """ - ws = await self._connect_ws(self.__extra_query, self.__extra_headers) - - self.__connection = AsyncTerminalsResourceConnection( - ws, - make_ws=self._connect_ws if self.__on_reconnecting is not None else None, - on_reconnecting=self.__on_reconnecting, - max_retries=self.__max_retries, - initial_delay=self.__initial_delay, - max_delay=self.__max_delay, - extra_query=self.__extra_query, - extra_headers=self.__extra_headers, - send_queue=self.__send_queue, - ) - - self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) - await self.__connection._flush_send_queue() - - return self.__connection - - enter = __aenter__ - - async def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> AsyncWebSocketConnection: - try: - from websockets.asyncio.client import connect - except ImportError as exc: - raise DedalusError("You need to install `dedalus-sdk[websockets]` to use this method") from exc - - if not self.__machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {self.__machine_id!r}") - if not self.__terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {self.__terminal_id!r}") - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - return await connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **self.__client.auth_headers, - }, - extra_headers, - ), - **self.__websocket_connection_options, - ) - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - scheme = self.__client._base_url.scheme - ws_scheme = "ws" if scheme == "http" else "wss" - base_url = self.__client._base_url.copy_with(scheme=ws_scheme) - - merge_raw_path = base_url.raw_path.rstrip(b"/") + path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}/stream", - machine_id=self.__machine_id, - terminal_id=self.__terminal_id, - ).encode("utf-8") - return base_url.copy_with(raw_path=merge_raw_path) - - async def __aexit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - await self.__connection.close() - - -class TerminalsResourceConnection: - """Represents a live WebSocket connection to the Terminals API""" - - _connection: WebSocketConnection - - def __init__( - self, - connection: WebSocketConnection, - *, - make_ws: Callable[[Query, Headers], WebSocketConnection] | None = None, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - extra_query: Query = {}, - extra_headers: Headers = {}, - send_queue: SendQueue | None = None, - ) -> None: - self._connection = connection - self._make_ws = make_ws - self._on_reconnecting = on_reconnecting - self._max_retries = max_retries - self._initial_delay = initial_delay - self._max_delay = max_delay - self._extra_query = extra_query - self._extra_headers = extra_headers - self._intentionally_closed = False - self._is_reconnecting = False - self._send_queue = send_queue or SendQueue() - self._event_handler_registry = EventHandlerRegistry(use_lock=True) - - def __iter__(self) -> Iterator[TerminalServerEvent]: - """ - An infinite-iterator that will continue to yield events until - the connection is closed. - """ - from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError - - while True: - try: - yield self.recv() - except ConnectionClosedOK: - return - except ConnectionClosedError as exc: - if not self._reconnect(exc): - unsent = self._send_queue.drain() - if unsent: - raise WebSocketConnectionClosedError( - "WebSocket connection closed with unsent messages", - unsent_messages=unsent, - ) from exc - raise - - def recv(self) -> TerminalServerEvent: - """ - Receive the next message from the connection and parses it into a `TerminalServerEvent` object. - - Canceling this method is safe. There's no risk of losing data. - """ - return self.parse_event(self.recv_bytes()) - - def recv_bytes(self) -> bytes: - """Receive the next message from the connection as raw bytes. - - Canceling this method is safe. There's no risk of losing data. - - If you want to parse the message into a `TerminalServerEvent` object like `.recv()` does, - then you can call `.parse_event(data)`. - """ - message = self._connection.recv(decode=False) - log.debug(f"Received WebSocket message: %s", message) - return message - - def send(self, event: TerminalClientEvent | TerminalClientEventParam) -> None: - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(maybe_transform(event, TerminalClientEventParam)) - ) - if self._is_reconnecting: - self._send_queue.enqueue(data) - return - try: - self._connection.send(data) - except Exception: - self._send_queue.enqueue(data) - raise - - def send_raw(self, data: bytes | str) -> None: - if self._is_reconnecting: - raw = data if isinstance(data, str) else data.decode("utf-8") - self._send_queue.enqueue(raw) - return - self._connection.send(data) - - def close(self, *, code: int = 1000, reason: str = "") -> None: - self._intentionally_closed = True - self._connection.close(code=code, reason=reason) - - def parse_event(self, data: str | bytes) -> TerminalServerEvent: - """ - Converts a raw `str` or `bytes` message into a `TerminalServerEvent` object. - - This is helpful if you're using `.recv_bytes()`. - """ - return cast( - TerminalServerEvent, construct_type_unchecked(value=json.loads(data), type_=cast(Any, TerminalServerEvent)) - ) - - def _reconnect(self, exc: Exception) -> bool: - """Attempt to reconnect after a connection failure. - - Returns ``True`` if a new connection was established, ``False`` if the - caller should re-raise the original exception. - """ - if self._on_reconnecting is None or self._make_ws is None: - return False - - from websockets.exceptions import ConnectionClosedError - - close_code = 1006 - if isinstance(exc, ConnectionClosedError) and exc.rcvd is not None: - close_code = exc.rcvd.code - - if not is_recoverable_close(close_code): - return False - - self._is_reconnecting = True - - for attempt in range(1, self._max_retries + 1): - base_delay = min(self._initial_delay * (2 ** (attempt - 1)), self._max_delay) - jitter = 0.75 + random.random() * 0.25 - delay = base_delay * jitter - - event = ReconnectingEvent( - attempt=attempt, - max_attempts=self._max_retries, - delay=delay, - close_code=close_code, - extra_query=self._extra_query, - extra_headers=self._extra_headers, - ) - - try: - result = self._on_reconnecting(event) - except Exception: - self._is_reconnecting = False - return False - - if result is not None and result.get("abort"): - self._is_reconnecting = False - return False - - if result is not None: - if "extra_query" in result: - self._extra_query = result["extra_query"] - if "extra_headers" in result: - self._extra_headers = result["extra_headers"] - - log.info( - "Reconnecting to WebSocket API (attempt %d/%d) after %.1fs delay", - attempt, - self._max_retries, - delay, - ) - time.sleep(delay) - - if self._intentionally_closed: - self._is_reconnecting = False - return False - - try: - self._connection = self._make_ws(self._extra_query, self._extra_headers) - log.info("Reconnected to WebSocket API") - self._is_reconnecting = False - self._flush_send_queue() - return True - except Exception: - pass - - self._is_reconnecting = False - return False - - def _flush_send_queue(self) -> None: - """Send all queued messages over the current connection.""" - try: - self._send_queue.flush_sync(lambda data: self._connection.send(data)) - except Exception: - log.warning("Failed to flush send queue after reconnect", exc_info=True) - - def on( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[TerminalsResourceConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Adds the handler to the end of the handlers list for the given event type. - - No checks are made to see if the handler has already been added. Multiple calls - passing the same combination of event type and handler will result in the handler - being added, and called, multiple times. - - Can be used as a method (returns ``self`` for chaining):: - - connection.on("output", my_handler) - - Or as a decorator:: - - @connection.on("output") - def my_handler(event): ... - """ - if handler is not None: - self._event_handler_registry.add(event_type, handler) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self._event_handler_registry.add(event_type, fn) - return fn - - return decorator - - def off(self, event_type: str, handler: Callable[..., Any]) -> TerminalsResourceConnection: - """Remove a previously registered event handler.""" - self._event_handler_registry.remove(event_type, handler) - return self - - def once( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[TerminalsResourceConnection, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register a one-time event handler. - - Automatically removed after first invocation. - """ - if handler is not None: - self._event_handler_registry.add(event_type, handler, once=True) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self._event_handler_registry.add(event_type, fn, once=True) - return fn - - return decorator - - def dispatch_events(self) -> None: - """Run the event loop, dispatching received events to registered handlers. - - Blocks the current thread until the connection is closed. This is the push-based - alternative to iterating with ``for event in connection``. - - If an ``"error"`` event arrives and no handler is registered for - ``"error"`` or ``"event"``, an ``DedalusError`` is raised. - """ - for event in self: - event_type = event.type - specific = self._event_handler_registry.get_handlers(event_type) - generic = self._event_handler_registry.get_handlers("event") - - if event_type == "error" and not specific and not generic: - if isinstance(event, TerminalErrorEvent): - raise DedalusError(f"WebSocket error: {event}") - - for handler in specific: - handler(event) - - for handler in generic: - handler(event) - - -class TerminalsResourceConnectionManager: - """ - Context manager over a `TerminalsResourceConnection` that is returned by `machines.terminals.connect()` - - This context manager ensures that the connection will be closed when it exits. - - --- - - Note that if your application doesn't work well with the context manager approach then you - can call the `.enter()` method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.machines.terminals.connect(...).enter() - # ... - connection.close() - ``` - """ - - def __init__( - self, - *, - client: Dedalus, - machine_id: str, - terminal_id: str, - extra_query: Query, - extra_headers: Headers, - websocket_connection_options: WebSocketConnectionOptions, - on_reconnecting: Callable[[ReconnectingEvent], ReconnectingOverrides | None] | None = None, - max_retries: int = 5, - initial_delay: float = 0.5, - max_delay: float = 8.0, - max_queue_size: int = 1_048_576, - ) -> None: - self.__client = client - self.__machine_id = machine_id - self.__terminal_id = terminal_id - self.__connection: TerminalsResourceConnection | None = None - self.__extra_query = extra_query - self.__extra_headers = extra_headers - self.__websocket_connection_options = websocket_connection_options - self.__on_reconnecting = on_reconnecting - self.__max_retries = max_retries - self.__initial_delay = initial_delay - self.__max_delay = max_delay - self.__send_queue = SendQueue(max_bytes=max_queue_size) - self.__event_handler_registry = EventHandlerRegistry(use_lock=True) - - def send(self, event: TerminalClientEvent | TerminalClientEventParam) -> None: - """Queue a message to be sent when the connection is established. - - This can be called before entering the context manager. Queued messages - are automatically sent once the WebSocket connection opens. - """ - data = ( - event.to_json(use_api_names=True, exclude_defaults=True, exclude_unset=True) - if isinstance(event, BaseModel) - else json.dumps(event) - ) - self.__send_queue.enqueue(data) - - def on( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[TerminalsResourceConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register an event handler before the connection is established. - - Handlers are transferred to the connection on enter. Supports the - same method and decorator forms as ``TerminalsResourceConnection.on``. - """ - if handler is not None: - self.__event_handler_registry.add(event_type, handler) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self.__event_handler_registry.add(event_type, fn) - return fn - - return decorator - - def off(self, event_type: str, handler: Callable[..., Any]) -> TerminalsResourceConnectionManager: - """Remove a previously registered event handler.""" - self.__event_handler_registry.remove(event_type, handler) - return self - - def once( - self, event_type: str, handler: Callable[..., Any] | None = None - ) -> Union[TerminalsResourceConnectionManager, Callable[[Callable[..., Any]], Callable[..., Any]]]: - """Register a one-time event handler before the connection is established.""" - if handler is not None: - self.__event_handler_registry.add(event_type, handler, once=True) - return self - - def decorator(fn: Callable[..., Any]) -> Callable[..., Any]: - self.__event_handler_registry.add(event_type, fn, once=True) - return fn - - return decorator - - def __enter__(self) -> TerminalsResourceConnection: - """ - If your application doesn't work well with the context manager approach then you - can call this method directly to initiate a connection. - - **Warning**: You must remember to close the connection with `.close()`. - - ```py - connection = client.machines.terminals.connect(...).enter() - # ... - connection.close() - ``` - """ - ws = self._connect_ws(self.__extra_query, self.__extra_headers) - - self.__connection = TerminalsResourceConnection( - ws, - make_ws=self._connect_ws if self.__on_reconnecting is not None else None, - on_reconnecting=self.__on_reconnecting, - max_retries=self.__max_retries, - initial_delay=self.__initial_delay, - max_delay=self.__max_delay, - extra_query=self.__extra_query, - extra_headers=self.__extra_headers, - send_queue=self.__send_queue, - ) - - self.__event_handler_registry.merge_into(self.__connection._event_handler_registry) - self.__connection._flush_send_queue() - - return self.__connection - - enter = __enter__ - - def _connect_ws(self, extra_query: Query, extra_headers: Headers) -> WebSocketConnection: - try: - from websockets.sync.client import connect - except ImportError as exc: - raise DedalusError("You need to install `dedalus-sdk[websockets]` to use this method") from exc - - if not self.__machine_id: - raise ValueError(f"Expected a non-empty value for `machine_id` but received {self.__machine_id!r}") - if not self.__terminal_id: - raise ValueError(f"Expected a non-empty value for `terminal_id` but received {self.__terminal_id!r}") - url = self._prepare_url().copy_with( - params={ - **self.__client.base_url.params, - **extra_query, - }, - ) - log.debug("Connecting to %s", url) - if self.__websocket_connection_options: - log.debug("Connection options: %s", self.__websocket_connection_options) - - return connect( - str(url), - user_agent_header=self.__client.user_agent, - additional_headers=_merge_mappings( - { - **self.__client.auth_headers, - }, - extra_headers, - ), - **self.__websocket_connection_options, - ) - - def _prepare_url(self) -> httpx.URL: - if self.__client.websocket_base_url is not None: - base_url = httpx.URL(self.__client.websocket_base_url) - else: - scheme = self.__client._base_url.scheme - ws_scheme = "ws" if scheme == "http" else "wss" - base_url = self.__client._base_url.copy_with(scheme=ws_scheme) - - merge_raw_path = base_url.raw_path.rstrip(b"/") + path_template( - "/v1/machines/{machine_id}/terminals/{terminal_id}/stream", - machine_id=self.__machine_id, - terminal_id=self.__terminal_id, - ).encode("utf-8") - return base_url.copy_with(raw_path=merge_raw_path) - - def __exit__( - self, exc_type: type[BaseException] | None, exc: BaseException | None, exc_tb: TracebackType | None - ) -> None: - if self.__connection is not None: - self.__connection.close() diff --git a/src/dedalus_sdk/resources/usage.py b/src/dedalus_sdk/resources/usage.py deleted file mode 100644 index b55009d..0000000 --- a/src/dedalus_sdk/resources/usage.py +++ /dev/null @@ -1,411 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ..types import usage_retrieve_params, usage_machine_compute_params, usage_machine_storage_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 .._base_client import make_request_options -from ..types.org_usage import OrgUsage -from ..types.machine_compute_usage import MachineComputeUsage -from ..types.machine_storage_usage import MachineStorageUsage - -__all__ = ["UsageResource", "AsyncUsageResource"] - - -class UsageResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> UsageResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return UsageResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> UsageResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return UsageResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - period_start: 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, - ) -> OrgUsage: - """Get usage summary - - Args: - period_start: Billing period start (YYYY-MM-DD). - - Defaults to first of current month. - - 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( - "/v1/usage", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"period_start": period_start}, usage_retrieve_params.UsageRetrieveParams), - ), - cast_to=OrgUsage, - ) - - def machine_compute( - self, - *, - granularity: str | Omit = omit, - machine_id: str | Omit = omit, - period_end: str | Omit = omit, - period_start: 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, - ) -> MachineComputeUsage: - """ - List machine compute usage breakdown - - Args: - granularity: Usage breakdown granularity: hour or day. Defaults to hour. - - machine_id: Optional machine ID filter. - - period_end: Last UTC usage date to include (YYYY-MM-DD). Defaults to current time. - - period_start: Usage period start (YYYY-MM-DD). Defaults to first of current month. - - 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( - "/v1/usage/machines/compute", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "granularity": granularity, - "machine_id": machine_id, - "period_end": period_end, - "period_start": period_start, - }, - usage_machine_compute_params.UsageMachineComputeParams, - ), - ), - cast_to=MachineComputeUsage, - ) - - def machine_storage( - self, - *, - machine_id: str | Omit = omit, - period_end: str | Omit = omit, - period_start: 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, - ) -> MachineStorageUsage: - """ - List machine storage usage breakdown - - Args: - machine_id: Optional machine ID filter. - - period_end: Last UTC usage date to include (YYYY-MM-DD). Defaults to current time. - - period_start: Usage period start (YYYY-MM-DD). Defaults to first of current month. - - 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( - "/v1/usage/machines/storage", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "machine_id": machine_id, - "period_end": period_end, - "period_start": period_start, - }, - usage_machine_storage_params.UsageMachineStorageParams, - ), - ), - cast_to=MachineStorageUsage, - ) - - -class AsyncUsageResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncUsageResourceWithRawResponse: - """ - 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/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers - """ - return AsyncUsageResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncUsageResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response - """ - return AsyncUsageResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - period_start: 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, - ) -> OrgUsage: - """Get usage summary - - Args: - period_start: Billing period start (YYYY-MM-DD). - - Defaults to first of current month. - - 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( - "/v1/usage", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"period_start": period_start}, usage_retrieve_params.UsageRetrieveParams - ), - ), - cast_to=OrgUsage, - ) - - async def machine_compute( - self, - *, - granularity: str | Omit = omit, - machine_id: str | Omit = omit, - period_end: str | Omit = omit, - period_start: 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, - ) -> MachineComputeUsage: - """ - List machine compute usage breakdown - - Args: - granularity: Usage breakdown granularity: hour or day. Defaults to hour. - - machine_id: Optional machine ID filter. - - period_end: Last UTC usage date to include (YYYY-MM-DD). Defaults to current time. - - period_start: Usage period start (YYYY-MM-DD). Defaults to first of current month. - - 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( - "/v1/usage/machines/compute", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "granularity": granularity, - "machine_id": machine_id, - "period_end": period_end, - "period_start": period_start, - }, - usage_machine_compute_params.UsageMachineComputeParams, - ), - ), - cast_to=MachineComputeUsage, - ) - - async def machine_storage( - self, - *, - machine_id: str | Omit = omit, - period_end: str | Omit = omit, - period_start: 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, - ) -> MachineStorageUsage: - """ - List machine storage usage breakdown - - Args: - machine_id: Optional machine ID filter. - - period_end: Last UTC usage date to include (YYYY-MM-DD). Defaults to current time. - - period_start: Usage period start (YYYY-MM-DD). Defaults to first of current month. - - 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( - "/v1/usage/machines/storage", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "machine_id": machine_id, - "period_end": period_end, - "period_start": period_start, - }, - usage_machine_storage_params.UsageMachineStorageParams, - ), - ), - cast_to=MachineStorageUsage, - ) - - -class UsageResourceWithRawResponse: - def __init__(self, usage: UsageResource) -> None: - self._usage = usage - - self.retrieve = to_raw_response_wrapper( - usage.retrieve, - ) - self.machine_compute = to_raw_response_wrapper( - usage.machine_compute, - ) - self.machine_storage = to_raw_response_wrapper( - usage.machine_storage, - ) - - -class AsyncUsageResourceWithRawResponse: - def __init__(self, usage: AsyncUsageResource) -> None: - self._usage = usage - - self.retrieve = async_to_raw_response_wrapper( - usage.retrieve, - ) - self.machine_compute = async_to_raw_response_wrapper( - usage.machine_compute, - ) - self.machine_storage = async_to_raw_response_wrapper( - usage.machine_storage, - ) - - -class UsageResourceWithStreamingResponse: - def __init__(self, usage: UsageResource) -> None: - self._usage = usage - - self.retrieve = to_streamed_response_wrapper( - usage.retrieve, - ) - self.machine_compute = to_streamed_response_wrapper( - usage.machine_compute, - ) - self.machine_storage = to_streamed_response_wrapper( - usage.machine_storage, - ) - - -class AsyncUsageResourceWithStreamingResponse: - def __init__(self, usage: AsyncUsageResource) -> None: - self._usage = usage - - self.retrieve = async_to_streamed_response_wrapper( - usage.retrieve, - ) - self.machine_compute = async_to_streamed_response_wrapper( - usage.machine_compute, - ) - self.machine_storage = async_to_streamed_response_wrapper( - usage.machine_storage, - ) diff --git a/src/dedalus_sdk/types/__init__.py b/src/dedalus_sdk/types/__init__.py index 446e783..6c1da62 100644 --- a/src/dedalus_sdk/types/__init__.py +++ b/src/dedalus_sdk/types/__init__.py @@ -3,22 +3,10 @@ from __future__ import annotations from .machine import Machine as Machine -from .org_usage import OrgUsage as OrgUsage from .machine_list import MachineList as MachineList from .lifecycle_status import LifecycleStatus as LifecycleStatus from .machine_list_item import MachineListItem as MachineListItem from .machine_list_params import MachineListParams as MachineListParams -from .machine_compute_usage import MachineComputeUsage as MachineComputeUsage from .machine_create_params import MachineCreateParams as MachineCreateParams -from .machine_storage_usage import MachineStorageUsage as MachineStorageUsage from .machine_update_params import MachineUpdateParams as MachineUpdateParams -from .usage_retrieve_params import UsageRetrieveParams as UsageRetrieveParams -from .websocket_reconnection import ( - ReconnectingEvent as ReconnectingEvent, - ReconnectingOverrides as ReconnectingOverrides, -) -from .machine_compute_usage_row import MachineComputeUsageRow as MachineComputeUsageRow -from .machine_storage_usage_row import MachineStorageUsageRow as MachineStorageUsageRow -from .usage_machine_compute_params import UsageMachineComputeParams as UsageMachineComputeParams -from .usage_machine_storage_params import UsageMachineStorageParams as UsageMachineStorageParams -from .websocket_connection_options import WebSocketConnectionOptions as WebSocketConnectionOptions +from .machine_retrieve_response import MachineRetrieveResponse as MachineRetrieveResponse diff --git a/src/dedalus_sdk/types/machine.py b/src/dedalus_sdk/types/machine.py index 750a1c1..cc707a2 100644 --- a/src/dedalus_sdk/types/machine.py +++ b/src/dedalus_sdk/types/machine.py @@ -3,7 +3,6 @@ from typing_extensions import Literal from .._models import BaseModel -from .lifecycle_status import LifecycleStatus __all__ = ["Machine"] @@ -19,7 +18,17 @@ class Machine(BaseModel): memory_mib: int """Memory in MiB.""" - status: LifecycleStatus + phase: Literal[ + "accepted", + "placement_pending", + "starting", + "running", + "stopping", + "sleeping", + "destroying", + "destroyed", + "failed", + ] storage_gib: int diff --git a/src/dedalus_sdk/types/machine_compute_usage.py b/src/dedalus_sdk/types/machine_compute_usage.py deleted file mode 100644 index d762f4f..0000000 --- a/src/dedalus_sdk/types/machine_compute_usage.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel -from .machine_compute_usage_row import MachineComputeUsageRow - -__all__ = ["MachineComputeUsage"] - - -class MachineComputeUsage(BaseModel): - granularity: str - """Usage breakdown granularity used for rows: hour or day.""" - - period_end: datetime - """Exclusive usage period end.""" - - period_start: datetime - """Inclusive usage period start.""" - - rows: Optional[List[MachineComputeUsageRow]] = None - """Machine-level compute usage breakdown rows.""" diff --git a/src/dedalus_sdk/types/machine_compute_usage_row.py b/src/dedalus_sdk/types/machine_compute_usage_row.py deleted file mode 100644 index dad85a9..0000000 --- a/src/dedalus_sdk/types/machine_compute_usage_row.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["MachineComputeUsageRow"] - - -class MachineComputeUsageRow(BaseModel): - awake_seconds: int - """Machine-awake seconds in this bucket.""" - - bucket_end: datetime - """Exclusive usage bucket end.""" - - bucket_start: datetime - """Inclusive usage bucket start.""" - - cpu_millicore_seconds: int - """Requested vCPU millicores multiplied by guest-owned active CPU seconds.""" - - last_window_end: datetime - """Latest raw window_end represented by this row.""" - - machine_id: str - """Machine identifier.""" - - memory_mib_seconds: int - """Requested memory MiB multiplied by running allocation seconds.""" - - org_metering_bucket_ids: Optional[List[str]] = None - """Org compute bucket IDs this row contributes to.""" - - requested_memory_mib: int - """Requested memory for this shape, in MiB.""" - - requested_storage_gib: int - """Requested storage for this shape, in GiB.""" - - requested_vcpu: float - """Requested vCPU for this shape.""" - - spec_fingerprint: str - """Stable fingerprint for the requested machine shape.""" - - stripe_cpu_identifiers: Optional[List[str]] = None - """Stripe CPU meter event identifiers linked to those org buckets.""" - - stripe_memory_identifiers: Optional[List[str]] = None - """Stripe memory meter event identifiers linked to those org buckets.""" - - window_count: int - """Raw usage windows compacted into this row.""" - - latest_stripe_emitted_at: Optional[datetime] = None - """Latest Stripe emission timestamp for linked org buckets, when emitted.""" diff --git a/src/dedalus_sdk/types/machine_create_params.py b/src/dedalus_sdk/types/machine_create_params.py index 50df48b..1a39a10 100644 --- a/src/dedalus_sdk/types/machine_create_params.py +++ b/src/dedalus_sdk/types/machine_create_params.py @@ -2,24 +2,24 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import TypedDict __all__ = ["MachineCreateParams"] class MachineCreateParams(TypedDict, total=False): - memory_mib: Required[int] - """Memory in MiB.""" - - storage_gib: Required[int] - """Storage in GiB.""" - - vcpu: Required[float] - """CPU in vCPUs.""" - autosleep: str """Idle window before autosleep. Accepts fixed duration units like 30s, 30m, 2h, 7d3h4s, or 1w3d, raw seconds ("1800"), or never to disable. """ + + memory_mib: int + """Memory in MiB.""" + + storage_gib: int + """Storage in GiB.""" + + vcpu: float + """CPU in vCPUs.""" diff --git a/src/dedalus_sdk/types/machine_list_item.py b/src/dedalus_sdk/types/machine_list_item.py index cb63899..440d90a 100644 --- a/src/dedalus_sdk/types/machine_list_item.py +++ b/src/dedalus_sdk/types/machine_list_item.py @@ -4,7 +4,6 @@ from typing_extensions import Literal from .._models import BaseModel -from .lifecycle_status import LifecycleStatus __all__ = ["MachineListItem"] @@ -22,7 +21,17 @@ class MachineListItem(BaseModel): memory_mib: int """Memory in MiB.""" - status: LifecycleStatus + phase: Literal[ + "accepted", + "placement_pending", + "starting", + "running", + "stopping", + "sleeping", + "destroying", + "destroyed", + "failed", + ] storage_gib: int diff --git a/src/dedalus_sdk/types/machine_retrieve_response.py b/src/dedalus_sdk/types/machine_retrieve_response.py new file mode 100644 index 0000000..009a023 --- /dev/null +++ b/src/dedalus_sdk/types/machine_retrieve_response.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel +from .lifecycle_status import LifecycleStatus + +__all__ = ["MachineRetrieveResponse"] + + +class MachineRetrieveResponse(BaseModel): + autosleep_seconds: int + """Seconds of inactivity before autosleep. 0 disables autosleep.""" + + desired_state: Literal["running", "sleeping", "destroyed"] + + machine_id: str + + memory_mib: int + """Memory in MiB.""" + + status: LifecycleStatus + + storage_gib: int + + vcpu: float + """CPU in vCPUs.""" diff --git a/src/dedalus_sdk/types/machine_storage_usage.py b/src/dedalus_sdk/types/machine_storage_usage.py deleted file mode 100644 index 795d271..0000000 --- a/src/dedalus_sdk/types/machine_storage_usage.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from .._models import BaseModel -from .machine_storage_usage_row import MachineStorageUsageRow - -__all__ = ["MachineStorageUsage"] - - -class MachineStorageUsage(BaseModel): - period_end: datetime - """Exclusive usage period end.""" - - period_start: datetime - """Inclusive usage period start.""" - - rows: Optional[List[MachineStorageUsageRow]] = None - """Machine-level storage usage breakdown rows.""" diff --git a/src/dedalus_sdk/types/machine_storage_usage_row.py b/src/dedalus_sdk/types/machine_storage_usage_row.py deleted file mode 100644 index 88becc2..0000000 --- a/src/dedalus_sdk/types/machine_storage_usage_row.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from .._models import BaseModel - -__all__ = ["MachineStorageUsageRow"] - - -class MachineStorageUsageRow(BaseModel): - bucket_end: datetime - """Exclusive usage bucket end.""" - - bucket_start: datetime - """Inclusive usage bucket start.""" - - logical_storage_bytes: int - """Machine logical bytes observed for storage allocation.""" - - machine_id: str - """Machine identifier.""" - - org_metering_bucket_id: str - """Org storage bucket ID this row contributes to.""" - - storage_mib_seconds: int - """Allocated logical MiB-seconds for this machine.""" - - stripe_storage_identifier: str - """Stripe storage meter event identifier linked to that org bucket.""" - - latest_stripe_emitted_at: Optional[datetime] = None - """Latest Stripe emission timestamp for the linked org bucket, when emitted.""" diff --git a/src/dedalus_sdk/types/machines/__init__.py b/src/dedalus_sdk/types/machines/__init__.py index 56ca47f..bf1af89 100644 --- a/src/dedalus_sdk/types/machines/__init__.py +++ b/src/dedalus_sdk/types/machines/__init__.py @@ -2,15 +2,9 @@ from __future__ import annotations -from .preview import Preview as Preview -from .artifact import Artifact as Artifact -from .terminal import Terminal as Terminal from .execution import Execution as Execution from .ssh_session import SSHSession as SSHSession from .artifact_ref import ArtifactRef as ArtifactRef -from .preview_list import PreviewList as PreviewList -from .artifact_list import ArtifactList as ArtifactList -from .terminal_list import TerminalList as TerminalList from .execution_list import ExecutionList as ExecutionList from .ssh_connection import SSHConnection as SSHConnection from .ssh_host_trust import SSHHostTrust as SSHHostTrust @@ -20,21 +14,6 @@ from .execution_output import ExecutionOutput as ExecutionOutput from .ssh_session_list import SSHSessionList as SSHSessionList from .ssh_create_params import SSHCreateParams as SSHCreateParams -from .preview_list_params import PreviewListParams as PreviewListParams -from .artifact_list_params import ArtifactListParams as ArtifactListParams -from .terminal_error_event import TerminalErrorEvent as TerminalErrorEvent -from .terminal_input_event import TerminalInputEvent as TerminalInputEvent -from .terminal_list_params import TerminalListParams as TerminalListParams from .execution_list_params import ExecutionListParams as ExecutionListParams -from .preview_create_params import PreviewCreateParams as PreviewCreateParams -from .terminal_client_event import TerminalClientEvent as TerminalClientEvent -from .terminal_closed_event import TerminalClosedEvent as TerminalClosedEvent -from .terminal_output_event import TerminalOutputEvent as TerminalOutputEvent -from .terminal_resize_event import TerminalResizeEvent as TerminalResizeEvent -from .terminal_server_event import TerminalServerEvent as TerminalServerEvent -from .terminal_create_params import TerminalCreateParams as TerminalCreateParams from .execution_create_params import ExecutionCreateParams as ExecutionCreateParams from .execution_events_params import ExecutionEventsParams as ExecutionEventsParams -from .terminal_input_event_param import TerminalInputEventParam as TerminalInputEventParam -from .terminal_client_event_param import TerminalClientEventParam as TerminalClientEventParam -from .terminal_resize_event_param import TerminalResizeEventParam as TerminalResizeEventParam diff --git a/src/dedalus_sdk/types/machines/artifact.py b/src/dedalus_sdk/types/machines/artifact.py deleted file mode 100644 index 2a75d0d..0000000 --- a/src/dedalus_sdk/types/machines/artifact.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["Artifact"] - - -class Artifact(BaseModel): - artifact_id: str - - created_at: datetime - - machine_id: str - - name: str - - size_bytes: int - - download_url: Optional[str] = None - - execution_id: Optional[str] = None - - expires_at: Optional[datetime] = None - - mime_type: Optional[str] = None - - sha256: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/artifact_list.py b/src/dedalus_sdk/types/machines/artifact_list.py deleted file mode 100644 index 88ff211..0000000 --- a/src/dedalus_sdk/types/machines/artifact_list.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .artifact import Artifact -from ..._models import BaseModel - -__all__ = ["ArtifactList"] - - -class ArtifactList(BaseModel): - items: Optional[List[Artifact]] = None - - next_cursor: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/artifact_list_params.py b/src/dedalus_sdk/types/machines/artifact_list_params.py deleted file mode 100644 index 61f41a1..0000000 --- a/src/dedalus_sdk/types/machines/artifact_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ArtifactListParams"] - - -class ArtifactListParams(TypedDict, total=False): - machine_id: Required[str] - - cursor: str - - limit: int diff --git a/src/dedalus_sdk/types/machines/preview.py b/src/dedalus_sdk/types/machines/preview.py deleted file mode 100644 index 760ac82..0000000 --- a/src/dedalus_sdk/types/machines/preview.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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 ..._models import BaseModel - -__all__ = ["Preview"] - - -class Preview(BaseModel): - created_at: datetime - - machine_id: str - - port: int - - preview_id: str - - status: Literal["wake_in_progress", "ready", "closed", "expired", "failed"] - - visibility: Literal["public", "private", "org"] - - error_code: Optional[str] = None - - error_message: Optional[str] = None - - expires_at: Optional[datetime] = None - - protocol: Optional[Literal["http", "https"]] = None - - ready_at: Optional[datetime] = None - - retry_after_ms: Optional[int] = None - - url: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/preview_create_params.py b/src/dedalus_sdk/types/machines/preview_create_params.py deleted file mode 100644 index 9e9f9e8..0000000 --- a/src/dedalus_sdk/types/machines/preview_create_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PreviewCreateParams"] - - -class PreviewCreateParams(TypedDict, total=False): - machine_id: Required[str] - - port: Required[int] - - protocol: Literal["http", "https"] - - visibility: Literal["public", "private", "org"] diff --git a/src/dedalus_sdk/types/machines/preview_list.py b/src/dedalus_sdk/types/machines/preview_list.py deleted file mode 100644 index 5cc0abe..0000000 --- a/src/dedalus_sdk/types/machines/preview_list.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .preview import Preview -from ..._models import BaseModel - -__all__ = ["PreviewList"] - - -class PreviewList(BaseModel): - items: Optional[List[Preview]] = None - - next_cursor: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/preview_list_params.py b/src/dedalus_sdk/types/machines/preview_list_params.py deleted file mode 100644 index e1050f0..0000000 --- a/src/dedalus_sdk/types/machines/preview_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PreviewListParams"] - - -class PreviewListParams(TypedDict, total=False): - machine_id: Required[str] - - cursor: str - - limit: int diff --git a/src/dedalus_sdk/types/machines/terminal.py b/src/dedalus_sdk/types/machines/terminal.py deleted file mode 100644 index 2897d3e..0000000 --- a/src/dedalus_sdk/types/machines/terminal.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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 ..._models import BaseModel - -__all__ = ["Terminal"] - - -class Terminal(BaseModel): - created_at: datetime - - height: int - - machine_id: str - - status: Literal["wake_in_progress", "ready", "closed", "expired", "failed"] - - terminal_id: str - - width: int - - error_code: Optional[str] = None - - error_message: Optional[str] = None - - expires_at: Optional[datetime] = None - - protocol: Optional[Literal["websocket"]] = None - - ready_at: Optional[datetime] = None - - retry_after_ms: Optional[int] = None - - stream_url: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/terminal_client_event.py b/src/dedalus_sdk/types/machines/terminal_client_event.py deleted file mode 100644 index 94fb770..0000000 --- a/src/dedalus_sdk/types/machines/terminal_client_event.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .terminal_input_event import TerminalInputEvent -from .terminal_resize_event import TerminalResizeEvent - -__all__ = ["TerminalClientEvent"] - -TerminalClientEvent: TypeAlias = Annotated[ - Union[TerminalInputEvent, TerminalResizeEvent], PropertyInfo(discriminator="type") -] diff --git a/src/dedalus_sdk/types/machines/terminal_client_event_param.py b/src/dedalus_sdk/types/machines/terminal_client_event_param.py deleted file mode 100644 index d309564..0000000 --- a/src/dedalus_sdk/types/machines/terminal_client_event_param.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import TypeAlias - -from .terminal_input_event_param import TerminalInputEventParam -from .terminal_resize_event_param import TerminalResizeEventParam - -__all__ = ["TerminalClientEventParam"] - -TerminalClientEventParam: TypeAlias = Union[TerminalInputEventParam, TerminalResizeEventParam] diff --git a/src/dedalus_sdk/types/machines/terminal_closed_event.py b/src/dedalus_sdk/types/machines/terminal_closed_event.py deleted file mode 100644 index 62c9e93..0000000 --- a/src/dedalus_sdk/types/machines/terminal_closed_event.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TerminalClosedEvent"] - - -class TerminalClosedEvent(BaseModel): - type: Literal["closed"] diff --git a/src/dedalus_sdk/types/machines/terminal_create_params.py b/src/dedalus_sdk/types/machines/terminal_create_params.py deleted file mode 100644 index 53b2a38..0000000 --- a/src/dedalus_sdk/types/machines/terminal_create_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Required, TypedDict - -__all__ = ["TerminalCreateParams"] - - -class TerminalCreateParams(TypedDict, total=False): - machine_id: Required[str] - - height: Required[int] - - width: Required[int] - - cwd: str - - env: Dict[str, str] - - shell: str diff --git a/src/dedalus_sdk/types/machines/terminal_error_event.py b/src/dedalus_sdk/types/machines/terminal_error_event.py deleted file mode 100644 index d1dd0d1..0000000 --- a/src/dedalus_sdk/types/machines/terminal_error_event.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TerminalErrorEvent"] - - -class TerminalErrorEvent(BaseModel): - type: Literal["error"] - - error_code: Optional[str] = None - - error_message: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/terminal_input_event.py b/src/dedalus_sdk/types/machines/terminal_input_event.py deleted file mode 100644 index 259f896..0000000 --- a/src/dedalus_sdk/types/machines/terminal_input_event.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TerminalInputEvent"] - - -class TerminalInputEvent(BaseModel): - data: str - """Base64-encoded terminal input.""" - - type: Literal["input"] diff --git a/src/dedalus_sdk/types/machines/terminal_input_event_param.py b/src/dedalus_sdk/types/machines/terminal_input_event_param.py deleted file mode 100644 index 17f1984..0000000 --- a/src/dedalus_sdk/types/machines/terminal_input_event_param.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import Base64FileInput -from ..._utils import PropertyInfo -from ..._models import set_pydantic_config - -__all__ = ["TerminalInputEventParam"] - - -class TerminalInputEventParam(TypedDict, total=False): - data: Required[Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")]] - """Base64-encoded terminal input.""" - - type: Required[Literal["input"]] - - -set_pydantic_config(TerminalInputEventParam, {"arbitrary_types_allowed": True}) diff --git a/src/dedalus_sdk/types/machines/terminal_list.py b/src/dedalus_sdk/types/machines/terminal_list.py deleted file mode 100644 index ebcbdd1..0000000 --- a/src/dedalus_sdk/types/machines/terminal_list.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from .terminal import Terminal -from ..._models import BaseModel - -__all__ = ["TerminalList"] - - -class TerminalList(BaseModel): - items: Optional[List[Terminal]] = None - - next_cursor: Optional[str] = None diff --git a/src/dedalus_sdk/types/machines/terminal_list_params.py b/src/dedalus_sdk/types/machines/terminal_list_params.py deleted file mode 100644 index cd723d6..0000000 --- a/src/dedalus_sdk/types/machines/terminal_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["TerminalListParams"] - - -class TerminalListParams(TypedDict, total=False): - machine_id: Required[str] - - cursor: str - - limit: int diff --git a/src/dedalus_sdk/types/machines/terminal_output_event.py b/src/dedalus_sdk/types/machines/terminal_output_event.py deleted file mode 100644 index a6fe0c5..0000000 --- a/src/dedalus_sdk/types/machines/terminal_output_event.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TerminalOutputEvent"] - - -class TerminalOutputEvent(BaseModel): - data: str - """Base64-encoded terminal output.""" - - type: Literal["output"] diff --git a/src/dedalus_sdk/types/machines/terminal_resize_event.py b/src/dedalus_sdk/types/machines/terminal_resize_event.py deleted file mode 100644 index b69dd07..0000000 --- a/src/dedalus_sdk/types/machines/terminal_resize_event.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["TerminalResizeEvent"] - - -class TerminalResizeEvent(BaseModel): - height: int - - type: Literal["resize"] - - width: int diff --git a/src/dedalus_sdk/types/machines/terminal_resize_event_param.py b/src/dedalus_sdk/types/machines/terminal_resize_event_param.py deleted file mode 100644 index 3b03e5e..0000000 --- a/src/dedalus_sdk/types/machines/terminal_resize_event_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TerminalResizeEventParam"] - - -class TerminalResizeEventParam(TypedDict, total=False): - height: Required[int] - - type: Required[Literal["resize"]] - - width: Required[int] diff --git a/src/dedalus_sdk/types/machines/terminal_server_event.py b/src/dedalus_sdk/types/machines/terminal_server_event.py deleted file mode 100644 index d51df44..0000000 --- a/src/dedalus_sdk/types/machines/terminal_server_event.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import Annotated, TypeAlias - -from ..._utils import PropertyInfo -from .terminal_error_event import TerminalErrorEvent -from .terminal_closed_event import TerminalClosedEvent -from .terminal_output_event import TerminalOutputEvent - -__all__ = ["TerminalServerEvent"] - -TerminalServerEvent: TypeAlias = Annotated[ - Union[TerminalOutputEvent, TerminalErrorEvent, TerminalClosedEvent], PropertyInfo(discriminator="type") -] diff --git a/src/dedalus_sdk/types/org_usage.py b/src/dedalus_sdk/types/org_usage.py deleted file mode 100644 index 482c546..0000000 --- a/src/dedalus_sdk/types/org_usage.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .._models import BaseModel - -__all__ = ["OrgUsage"] - - -class OrgUsage(BaseModel): - billed_awake_seconds: int - """Closed awake seconds in billed org buckets for the period.""" - - billed_cpu_millicore_seconds: int - """ - Closed requested vCPU millicores multiplied by guest-owned active CPU seconds - for the period. - """ - - billed_logical_storage_mib_seconds: int - """ - Closed billable logical MiB-seconds for the period, matching the Stripe storage - meter. - """ - - billed_memory_mib_seconds: int - """ - Closed requested memory MiB multiplied by running allocation seconds for the - period. - """ - - included_storage_gib: int - """Plan-included storage in GiB, used as a local guardrail only.""" - - plan_slug: str - """Billing plan in effect for the organization.""" - - provisioned_storage_gib: int - """Current provisioned storage summed across machines in GiB.""" diff --git a/src/dedalus_sdk/types/usage_machine_compute_params.py b/src/dedalus_sdk/types/usage_machine_compute_params.py deleted file mode 100644 index 9cc30c0..0000000 --- a/src/dedalus_sdk/types/usage_machine_compute_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["UsageMachineComputeParams"] - - -class UsageMachineComputeParams(TypedDict, total=False): - granularity: str - """Usage breakdown granularity: hour or day. Defaults to hour.""" - - machine_id: str - """Optional machine ID filter.""" - - period_end: str - """Last UTC usage date to include (YYYY-MM-DD). Defaults to current time.""" - - period_start: str - """Usage period start (YYYY-MM-DD). Defaults to first of current month.""" diff --git a/src/dedalus_sdk/types/usage_machine_storage_params.py b/src/dedalus_sdk/types/usage_machine_storage_params.py deleted file mode 100644 index 35d8e07..0000000 --- a/src/dedalus_sdk/types/usage_machine_storage_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["UsageMachineStorageParams"] - - -class UsageMachineStorageParams(TypedDict, total=False): - machine_id: str - """Optional machine ID filter.""" - - period_end: str - """Last UTC usage date to include (YYYY-MM-DD). Defaults to current time.""" - - period_start: str - """Usage period start (YYYY-MM-DD). Defaults to first of current month.""" diff --git a/src/dedalus_sdk/types/usage_retrieve_params.py b/src/dedalus_sdk/types/usage_retrieve_params.py deleted file mode 100644 index 5170bf1..0000000 --- a/src/dedalus_sdk/types/usage_retrieve_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["UsageRetrieveParams"] - - -class UsageRetrieveParams(TypedDict, total=False): - period_start: str - """Billing period start (YYYY-MM-DD). Defaults to first of current month.""" diff --git a/src/dedalus_sdk/types/websocket_connection_options.py b/src/dedalus_sdk/types/websocket_connection_options.py deleted file mode 100644 index 36fcfa9..0000000 --- a/src/dedalus_sdk/types/websocket_connection_options.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import TYPE_CHECKING -from typing_extensions import Sequence, TypedDict - -if TYPE_CHECKING: - from websockets import Subprotocol - from websockets.extensions import ClientExtensionFactory - - -class WebSocketConnectionOptions(TypedDict, total=False): - """WebSocket connection options copied from `websockets`. - - For example: https://websockets.readthedocs.io/en/stable/reference/asyncio/client.html#websockets.asyncio.client.connect - """ - - extensions: Sequence[ClientExtensionFactory] | None - """List of supported extensions, in order in which they should be negotiated and run.""" - - subprotocols: Sequence[Subprotocol] | None - """List of supported subprotocols, in order of decreasing preference.""" - - compression: str | None - """The “permessage-deflate” extension is enabled by default. Set compression to None to disable it. See the [compression guide](https://websockets.readthedocs.io/en/stable/topics/compression.html) for details.""" - - # limits - max_size: int | None - """Maximum size of incoming messages in bytes. None disables the limit.""" - - max_queue: int | None | tuple[int | None, int | None] - """High-water mark of the buffer where frames are received. It defaults to 16 frames. The low-water mark defaults to max_queue // 4. You may pass a (high, low) tuple to set the high-water and low-water marks. If you want to disable flow control entirely, you may set it to None, although that’s a bad idea.""" - - write_limit: int | tuple[int, int | None] - """High-water mark of write buffer in bytes. It is passed to set_write_buffer_limits(). It defaults to 32 KiB. You may pass a (high, low) tuple to set the high-water and low-water marks.""" diff --git a/src/dedalus_sdk/types/websocket_reconnection.py b/src/dedalus_sdk/types/websocket_reconnection.py deleted file mode 100644 index 9ba66d0..0000000 --- a/src/dedalus_sdk/types/websocket_reconnection.py +++ /dev/null @@ -1,64 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import dataclasses -from typing_extensions import TypedDict - -from .._types import Query, Headers - - -@dataclasses.dataclass(frozen=True) -class ReconnectingEvent: - """Information about a reconnection attempt, passed to the ``on_reconnecting`` handler.""" - - attempt: int - """Which retry attempt this is (1-based).""" - - max_attempts: int - """Total attempts that will be made.""" - - delay: float - """Delay in seconds before this attempt connects.""" - - close_code: int - """The WebSocket close code that triggered reconnection.""" - - extra_query: Query - """The current query parameters.""" - - extra_headers: Headers - """The current headers.""" - - -class ReconnectingOverrides(TypedDict, total=False): - """Optional overrides returned from the ``on_reconnecting`` handler - to customize the next reconnection attempt.""" - - extra_query: Query - """If provided, assigns the query parameters for the next connection.""" - - extra_headers: Headers - """If provided, assigns the headers for the next connection.""" - - abort: bool - """If set to ``True``, will stop attempting to reconnect.""" - - -# RFC 6455 §7.4.1 -_RECOVERABLE_CLOSE_CODES: frozenset[int] = frozenset( - { - 1001, # Going away (server shutting down) - 1005, # No status code (abnormal) - 1006, # Abnormal closure (network drop) - 1011, # Internal server error - 1012, # Service restart - 1013, # Try again later - 1015, # TLS handshake failure - } -) - - -def is_recoverable_close(code: int) -> bool: - """Return ``True`` if the WebSocket close *code* is worth retrying.""" - return code in _RECOVERABLE_CLOSE_CODES diff --git a/tests/api_resources/machines/test_artifacts.py b/tests/api_resources/machines/test_artifacts.py deleted file mode 100644 index b4b6ff8..0000000 --- a/tests/api_resources/machines/test_artifacts.py +++ /dev/null @@ -1,311 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from dedalus_sdk import Dedalus, AsyncDedalus -from tests.utils import assert_matches_type -from dedalus_sdk.pagination import SyncCursorPage, AsyncCursorPage -from dedalus_sdk.types.machines import Artifact - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestArtifacts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Dedalus) -> None: - artifact = client.machines.artifacts.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Dedalus) -> None: - response = client.machines.artifacts.with_raw_response.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Dedalus) -> None: - with client.machines.artifacts.with_streaming_response.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.artifacts.with_raw_response.retrieve( - machine_id="", - artifact_id="artifact_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): - client.machines.artifacts.with_raw_response.retrieve( - machine_id="dm-3", - artifact_id="", - ) - - @parametrize - def test_method_list(self, client: Dedalus) -> None: - artifact = client.machines.artifacts.list( - machine_id="dm-3", - ) - assert_matches_type(SyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Dedalus) -> None: - artifact = client.machines.artifacts.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(SyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Dedalus) -> None: - response = client.machines.artifacts.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = response.parse() - assert_matches_type(SyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Dedalus) -> None: - with client.machines.artifacts.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = response.parse() - assert_matches_type(SyncCursorPage[Artifact], artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.artifacts.with_raw_response.list( - machine_id="", - ) - - @parametrize - def test_method_delete(self, client: Dedalus) -> None: - artifact = client.machines.artifacts.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Dedalus) -> None: - response = client.machines.artifacts.with_raw_response.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Dedalus) -> None: - with client.machines.artifacts.with_streaming_response.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.artifacts.with_raw_response.delete( - machine_id="", - artifact_id="artifact_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): - client.machines.artifacts.with_raw_response.delete( - machine_id="dm-3", - artifact_id="", - ) - - -class TestAsyncArtifacts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: - artifact = await async_client.machines.artifacts.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.artifacts.with_raw_response.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = await response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.artifacts.with_streaming_response.retrieve( - machine_id="dm-3", - artifact_id="artifact_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = await response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.artifacts.with_raw_response.retrieve( - machine_id="", - artifact_id="artifact_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): - await async_client.machines.artifacts.with_raw_response.retrieve( - machine_id="dm-3", - artifact_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncDedalus) -> None: - artifact = await async_client.machines.artifacts.list( - machine_id="dm-3", - ) - assert_matches_type(AsyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None: - artifact = await async_client.machines.artifacts.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(AsyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.artifacts.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = await response.parse() - assert_matches_type(AsyncCursorPage[Artifact], artifact, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.artifacts.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = await response.parse() - assert_matches_type(AsyncCursorPage[Artifact], artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.artifacts.with_raw_response.list( - machine_id="", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncDedalus) -> None: - artifact = await async_client.machines.artifacts.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.artifacts.with_raw_response.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - artifact = await response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.artifacts.with_streaming_response.delete( - machine_id="dm-3", - artifact_id="artifact_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - artifact = await response.parse() - assert_matches_type(Artifact, artifact, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.artifacts.with_raw_response.delete( - machine_id="", - artifact_id="artifact_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): - await async_client.machines.artifacts.with_raw_response.delete( - machine_id="dm-3", - artifact_id="", - ) diff --git a/tests/api_resources/machines/test_executions.py b/tests/api_resources/machines/test_executions.py index 85091f9..87ad5c2 100644 --- a/tests/api_resources/machines/test_executions.py +++ b/tests/api_resources/machines/test_executions.py @@ -25,7 +25,7 @@ class TestExecutions: @parametrize def test_method_create(self, client: Dedalus) -> None: execution = client.machines.executions.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) assert_matches_type(Execution, execution, path=["response"]) @@ -33,7 +33,7 @@ def test_method_create(self, client: Dedalus) -> None: @parametrize def test_method_create_with_all_params(self, client: Dedalus) -> None: execution = client.machines.executions.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], cwd="cwd", env={"foo": "string"}, @@ -45,7 +45,7 @@ def test_method_create_with_all_params(self, client: Dedalus) -> None: @parametrize def test_raw_response_create(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) @@ -57,7 +57,7 @@ def test_raw_response_create(self, client: Dedalus) -> None: @parametrize def test_streaming_response_create(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) as response: assert not response.is_closed @@ -79,7 +79,7 @@ def test_path_params_create(self, client: Dedalus) -> None: @parametrize def test_method_retrieve(self, client: Dedalus) -> None: execution = client.machines.executions.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(Execution, execution, path=["response"]) @@ -87,7 +87,7 @@ def test_method_retrieve(self, client: Dedalus) -> None: @parametrize def test_raw_response_retrieve(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -99,7 +99,7 @@ def test_raw_response_retrieve(self, client: Dedalus) -> None: @parametrize def test_streaming_response_retrieve(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -120,21 +120,21 @@ def test_path_params_retrieve(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): client.machines.executions.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize def test_method_list(self, client: Dedalus) -> None: execution = client.machines.executions.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(SyncCursorPage[Execution], execution, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Dedalus) -> None: execution = client.machines.executions.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", cursor="cursor", limit=0, ) @@ -143,7 +143,7 @@ def test_method_list_with_all_params(self, client: Dedalus) -> None: @parametrize def test_raw_response_list(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -154,7 +154,7 @@ def test_raw_response_list(self, client: Dedalus) -> None: @parametrize def test_streaming_response_list(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -174,7 +174,7 @@ def test_path_params_list(self, client: Dedalus) -> None: @parametrize def test_method_delete(self, client: Dedalus) -> None: execution = client.machines.executions.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(Execution, execution, path=["response"]) @@ -182,7 +182,7 @@ def test_method_delete(self, client: Dedalus) -> None: @parametrize def test_raw_response_delete(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -194,7 +194,7 @@ def test_raw_response_delete(self, client: Dedalus) -> None: @parametrize def test_streaming_response_delete(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -215,14 +215,14 @@ def test_path_params_delete(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): client.machines.executions.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize def test_method_events(self, client: Dedalus) -> None: execution = client.machines.executions.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(SyncCursorPage[ExecutionEvent], execution, path=["response"]) @@ -230,7 +230,7 @@ def test_method_events(self, client: Dedalus) -> None: @parametrize def test_method_events_with_all_params(self, client: Dedalus) -> None: execution = client.machines.executions.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", cursor="cursor", limit=0, @@ -240,7 +240,7 @@ def test_method_events_with_all_params(self, client: Dedalus) -> None: @parametrize def test_raw_response_events(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -252,7 +252,7 @@ def test_raw_response_events(self, client: Dedalus) -> None: @parametrize def test_streaming_response_events(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -273,14 +273,14 @@ def test_path_params_events(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): client.machines.executions.with_raw_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize def test_method_output(self, client: Dedalus) -> None: execution = client.machines.executions.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(ExecutionOutput, execution, path=["response"]) @@ -288,7 +288,7 @@ def test_method_output(self, client: Dedalus) -> None: @parametrize def test_raw_response_output(self, client: Dedalus) -> None: response = client.machines.executions.with_raw_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -300,7 +300,7 @@ def test_raw_response_output(self, client: Dedalus) -> None: @parametrize def test_streaming_response_output(self, client: Dedalus) -> None: with client.machines.executions.with_streaming_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -321,7 +321,7 @@ def test_path_params_output(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): client.machines.executions.with_raw_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @@ -334,7 +334,7 @@ class TestAsyncExecutions: @parametrize async def test_method_create(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) assert_matches_type(Execution, execution, path=["response"]) @@ -342,7 +342,7 @@ async def test_method_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], cwd="cwd", env={"foo": "string"}, @@ -354,7 +354,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncDedalus) - @parametrize async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) @@ -366,7 +366,7 @@ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", command=["string"], ) as response: assert not response.is_closed @@ -388,7 +388,7 @@ async def test_path_params_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(Execution, execution, path=["response"]) @@ -396,7 +396,7 @@ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -408,7 +408,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -429,21 +429,21 @@ async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): await async_client.machines.executions.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize async def test_method_list(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(AsyncCursorPage[Execution], execution, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", cursor="cursor", limit=0, ) @@ -452,7 +452,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> @parametrize async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -463,7 +463,7 @@ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -483,7 +483,7 @@ async def test_path_params_list(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_delete(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(Execution, execution, path=["response"]) @@ -491,7 +491,7 @@ async def test_method_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -503,7 +503,7 @@ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -524,14 +524,14 @@ async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): await async_client.machines.executions.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize async def test_method_events(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(AsyncCursorPage[ExecutionEvent], execution, path=["response"]) @@ -539,7 +539,7 @@ async def test_method_events(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_events_with_all_params(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", cursor="cursor", limit=0, @@ -549,7 +549,7 @@ async def test_method_events_with_all_params(self, async_client: AsyncDedalus) - @parametrize async def test_raw_response_events(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -561,7 +561,7 @@ async def test_raw_response_events(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_events(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -582,14 +582,14 @@ async def test_path_params_events(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): await async_client.machines.executions.with_raw_response.events( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) @parametrize async def test_method_output(self, async_client: AsyncDedalus) -> None: execution = await async_client.machines.executions.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) assert_matches_type(ExecutionOutput, execution, path=["response"]) @@ -597,7 +597,7 @@ async def test_method_output(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_output(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.executions.with_raw_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) @@ -609,7 +609,7 @@ async def test_raw_response_output(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_output(self, async_client: AsyncDedalus) -> None: async with async_client.machines.executions.with_streaming_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="execution_id", ) as response: assert not response.is_closed @@ -630,6 +630,6 @@ async def test_path_params_output(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"): await async_client.machines.executions.with_raw_response.output( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", execution_id="", ) diff --git a/tests/api_resources/machines/test_previews.py b/tests/api_resources/machines/test_previews.py deleted file mode 100644 index 271bac0..0000000 --- a/tests/api_resources/machines/test_previews.py +++ /dev/null @@ -1,415 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from dedalus_sdk import Dedalus, AsyncDedalus -from tests.utils import assert_matches_type -from dedalus_sdk.pagination import SyncCursorPage, AsyncCursorPage -from dedalus_sdk.types.machines import Preview - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPreviews: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Dedalus) -> None: - preview = client.machines.previews.create( - machine_id="dm-3", - port=0, - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Dedalus) -> None: - preview = client.machines.previews.create( - machine_id="dm-3", - port=0, - protocol="http", - visibility="public", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Dedalus) -> None: - response = client.machines.previews.with_raw_response.create( - machine_id="dm-3", - port=0, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Dedalus) -> None: - with client.machines.previews.with_streaming_response.create( - machine_id="dm-3", - port=0, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.previews.with_raw_response.create( - machine_id="", - port=0, - ) - - @parametrize - def test_method_retrieve(self, client: Dedalus) -> None: - preview = client.machines.previews.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Dedalus) -> None: - response = client.machines.previews.with_raw_response.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Dedalus) -> None: - with client.machines.previews.with_streaming_response.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.previews.with_raw_response.retrieve( - machine_id="", - preview_id="preview_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"): - client.machines.previews.with_raw_response.retrieve( - machine_id="dm-3", - preview_id="", - ) - - @parametrize - def test_method_list(self, client: Dedalus) -> None: - preview = client.machines.previews.list( - machine_id="dm-3", - ) - assert_matches_type(SyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Dedalus) -> None: - preview = client.machines.previews.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(SyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Dedalus) -> None: - response = client.machines.previews.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = response.parse() - assert_matches_type(SyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Dedalus) -> None: - with client.machines.previews.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = response.parse() - assert_matches_type(SyncCursorPage[Preview], preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.previews.with_raw_response.list( - machine_id="", - ) - - @parametrize - def test_method_delete(self, client: Dedalus) -> None: - preview = client.machines.previews.delete( - machine_id="dm-3", - preview_id="preview_id", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Dedalus) -> None: - response = client.machines.previews.with_raw_response.delete( - machine_id="dm-3", - preview_id="preview_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Dedalus) -> None: - with client.machines.previews.with_streaming_response.delete( - machine_id="dm-3", - preview_id="preview_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.previews.with_raw_response.delete( - machine_id="", - preview_id="preview_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"): - client.machines.previews.with_raw_response.delete( - machine_id="dm-3", - preview_id="", - ) - - -class TestAsyncPreviews: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.create( - machine_id="dm-3", - port=0, - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.create( - machine_id="dm-3", - port=0, - protocol="http", - visibility="public", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.previews.with_raw_response.create( - machine_id="dm-3", - port=0, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.previews.with_streaming_response.create( - machine_id="dm-3", - port=0, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.previews.with_raw_response.create( - machine_id="", - port=0, - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.previews.with_raw_response.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.previews.with_streaming_response.retrieve( - machine_id="dm-3", - preview_id="preview_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.previews.with_raw_response.retrieve( - machine_id="", - preview_id="preview_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"): - await async_client.machines.previews.with_raw_response.retrieve( - machine_id="dm-3", - preview_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.list( - machine_id="dm-3", - ) - assert_matches_type(AsyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(AsyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.previews.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = await response.parse() - assert_matches_type(AsyncCursorPage[Preview], preview, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.previews.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = await response.parse() - assert_matches_type(AsyncCursorPage[Preview], preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.previews.with_raw_response.list( - machine_id="", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncDedalus) -> None: - preview = await async_client.machines.previews.delete( - machine_id="dm-3", - preview_id="preview_id", - ) - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.previews.with_raw_response.delete( - machine_id="dm-3", - preview_id="preview_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.previews.with_streaming_response.delete( - machine_id="dm-3", - preview_id="preview_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - preview = await response.parse() - assert_matches_type(Preview, preview, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.previews.with_raw_response.delete( - machine_id="", - preview_id="preview_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"): - await async_client.machines.previews.with_raw_response.delete( - machine_id="dm-3", - preview_id="", - ) diff --git a/tests/api_resources/machines/test_ssh.py b/tests/api_resources/machines/test_ssh.py index fc6e80c..65ba42c 100644 --- a/tests/api_resources/machines/test_ssh.py +++ b/tests/api_resources/machines/test_ssh.py @@ -21,7 +21,7 @@ class TestSSH: @parametrize def test_method_create(self, client: Dedalus) -> None: ssh = client.machines.ssh.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -29,7 +29,7 @@ def test_method_create(self, client: Dedalus) -> None: @parametrize def test_raw_response_create(self, client: Dedalus) -> None: response = client.machines.ssh.with_raw_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) @@ -41,7 +41,7 @@ def test_raw_response_create(self, client: Dedalus) -> None: @parametrize def test_streaming_response_create(self, client: Dedalus) -> None: with client.machines.ssh.with_streaming_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) as response: assert not response.is_closed @@ -63,7 +63,7 @@ def test_path_params_create(self, client: Dedalus) -> None: @parametrize def test_method_retrieve(self, client: Dedalus) -> None: ssh = client.machines.ssh.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -71,7 +71,7 @@ def test_method_retrieve(self, client: Dedalus) -> None: @parametrize def test_raw_response_retrieve(self, client: Dedalus) -> None: response = client.machines.ssh.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) @@ -83,7 +83,7 @@ def test_raw_response_retrieve(self, client: Dedalus) -> None: @parametrize def test_streaming_response_retrieve(self, client: Dedalus) -> None: with client.machines.ssh.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) as response: assert not response.is_closed @@ -104,21 +104,21 @@ def test_path_params_retrieve(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): client.machines.ssh.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="", ) @parametrize def test_method_list(self, client: Dedalus) -> None: ssh = client.machines.ssh.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(SyncCursorPage[SSHSession], ssh, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Dedalus) -> None: ssh = client.machines.ssh.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", cursor="cursor", limit=0, ) @@ -127,7 +127,7 @@ def test_method_list_with_all_params(self, client: Dedalus) -> None: @parametrize def test_raw_response_list(self, client: Dedalus) -> None: response = client.machines.ssh.with_raw_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -138,7 +138,7 @@ def test_raw_response_list(self, client: Dedalus) -> None: @parametrize def test_streaming_response_list(self, client: Dedalus) -> None: with client.machines.ssh.with_streaming_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -158,7 +158,7 @@ def test_path_params_list(self, client: Dedalus) -> None: @parametrize def test_method_delete(self, client: Dedalus) -> None: ssh = client.machines.ssh.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -166,7 +166,7 @@ def test_method_delete(self, client: Dedalus) -> None: @parametrize def test_raw_response_delete(self, client: Dedalus) -> None: response = client.machines.ssh.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) @@ -178,7 +178,7 @@ def test_raw_response_delete(self, client: Dedalus) -> None: @parametrize def test_streaming_response_delete(self, client: Dedalus) -> None: with client.machines.ssh.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) as response: assert not response.is_closed @@ -199,7 +199,7 @@ def test_path_params_delete(self, client: Dedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): client.machines.ssh.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="", ) @@ -212,7 +212,7 @@ class TestAsyncSSH: @parametrize async def test_method_create(self, async_client: AsyncDedalus) -> None: ssh = await async_client.machines.ssh.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -220,7 +220,7 @@ async def test_method_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.ssh.with_raw_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) @@ -232,7 +232,7 @@ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None: async with async_client.machines.ssh.with_streaming_response.create( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", public_key="public_key", ) as response: assert not response.is_closed @@ -254,7 +254,7 @@ async def test_path_params_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: ssh = await async_client.machines.ssh.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -262,7 +262,7 @@ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.ssh.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) @@ -274,7 +274,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: async with async_client.machines.ssh.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) as response: assert not response.is_closed @@ -295,21 +295,21 @@ async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): await async_client.machines.ssh.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="", ) @parametrize async def test_method_list(self, async_client: AsyncDedalus) -> None: ssh = await async_client.machines.ssh.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(AsyncCursorPage[SSHSession], ssh, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None: ssh = await async_client.machines.ssh.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", cursor="cursor", limit=0, ) @@ -318,7 +318,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> @parametrize async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.ssh.with_raw_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -329,7 +329,7 @@ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None: async with async_client.machines.ssh.with_streaming_response.list( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -349,7 +349,7 @@ async def test_path_params_list(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_delete(self, async_client: AsyncDedalus) -> None: ssh = await async_client.machines.ssh.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) assert_matches_type(SSHSession, ssh, path=["response"]) @@ -357,7 +357,7 @@ async def test_method_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.ssh.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) @@ -369,7 +369,7 @@ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: async with async_client.machines.ssh.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="session_id", ) as response: assert not response.is_closed @@ -390,6 +390,6 @@ async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): await async_client.machines.ssh.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", session_id="", ) diff --git a/tests/api_resources/machines/test_terminals.py b/tests/api_resources/machines/test_terminals.py deleted file mode 100644 index ceacabc..0000000 --- a/tests/api_resources/machines/test_terminals.py +++ /dev/null @@ -1,427 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from dedalus_sdk import Dedalus, AsyncDedalus -from tests.utils import assert_matches_type -from dedalus_sdk.pagination import SyncCursorPage, AsyncCursorPage -from dedalus_sdk.types.machines import Terminal - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestTerminals: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Dedalus) -> None: - terminal = client.machines.terminals.create( - machine_id="dm-3", - height=0, - width=0, - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Dedalus) -> None: - terminal = client.machines.terminals.create( - machine_id="dm-3", - height=0, - width=0, - cwd="cwd", - env={"foo": "string"}, - shell="shell", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Dedalus) -> None: - response = client.machines.terminals.with_raw_response.create( - machine_id="dm-3", - height=0, - width=0, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Dedalus) -> None: - with client.machines.terminals.with_streaming_response.create( - machine_id="dm-3", - height=0, - width=0, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.terminals.with_raw_response.create( - machine_id="", - height=0, - width=0, - ) - - @parametrize - def test_method_retrieve(self, client: Dedalus) -> None: - terminal = client.machines.terminals.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Dedalus) -> None: - response = client.machines.terminals.with_raw_response.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Dedalus) -> None: - with client.machines.terminals.with_streaming_response.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.terminals.with_raw_response.retrieve( - machine_id="", - terminal_id="terminal_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"): - client.machines.terminals.with_raw_response.retrieve( - machine_id="dm-3", - terminal_id="", - ) - - @parametrize - def test_method_list(self, client: Dedalus) -> None: - terminal = client.machines.terminals.list( - machine_id="dm-3", - ) - assert_matches_type(SyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Dedalus) -> None: - terminal = client.machines.terminals.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(SyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Dedalus) -> None: - response = client.machines.terminals.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = response.parse() - assert_matches_type(SyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Dedalus) -> None: - with client.machines.terminals.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = response.parse() - assert_matches_type(SyncCursorPage[Terminal], terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.terminals.with_raw_response.list( - machine_id="", - ) - - @parametrize - def test_method_delete(self, client: Dedalus) -> None: - terminal = client.machines.terminals.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_raw_response_delete(self, client: Dedalus) -> None: - response = client.machines.terminals.with_raw_response.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - def test_streaming_response_delete(self, client: Dedalus) -> None: - with client.machines.terminals.with_streaming_response.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.terminals.with_raw_response.delete( - machine_id="", - terminal_id="terminal_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"): - client.machines.terminals.with_raw_response.delete( - machine_id="dm-3", - terminal_id="", - ) - - -class TestAsyncTerminals: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.create( - machine_id="dm-3", - height=0, - width=0, - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.create( - machine_id="dm-3", - height=0, - width=0, - cwd="cwd", - env={"foo": "string"}, - shell="shell", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.terminals.with_raw_response.create( - machine_id="dm-3", - height=0, - width=0, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.terminals.with_streaming_response.create( - machine_id="dm-3", - height=0, - width=0, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.terminals.with_raw_response.create( - machine_id="", - height=0, - width=0, - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.terminals.with_raw_response.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.terminals.with_streaming_response.retrieve( - machine_id="dm-3", - terminal_id="terminal_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.terminals.with_raw_response.retrieve( - machine_id="", - terminal_id="terminal_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"): - await async_client.machines.terminals.with_raw_response.retrieve( - machine_id="dm-3", - terminal_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.list( - machine_id="dm-3", - ) - assert_matches_type(AsyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.list( - machine_id="dm-3", - cursor="cursor", - limit=0, - ) - assert_matches_type(AsyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.terminals.with_raw_response.list( - machine_id="dm-3", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = await response.parse() - assert_matches_type(AsyncCursorPage[Terminal], terminal, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.terminals.with_streaming_response.list( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = await response.parse() - assert_matches_type(AsyncCursorPage[Terminal], terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.terminals.with_raw_response.list( - machine_id="", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncDedalus) -> None: - terminal = await async_client.machines.terminals.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.terminals.with_raw_response.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.terminals.with_streaming_response.delete( - machine_id="dm-3", - terminal_id="terminal_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - terminal = await response.parse() - assert_matches_type(Terminal, terminal, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.terminals.with_raw_response.delete( - machine_id="", - terminal_id="terminal_id", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"): - await async_client.machines.terminals.with_raw_response.delete( - machine_id="dm-3", - terminal_id="", - ) diff --git a/tests/api_resources/test_machines.py b/tests/api_resources/test_machines.py index 5e706dd..dbdfeef 100644 --- a/tests/api_resources/test_machines.py +++ b/tests/api_resources/test_machines.py @@ -12,6 +12,7 @@ from dedalus_sdk.types import ( Machine, MachineListItem, + MachineRetrieveResponse, ) from dedalus_sdk.pagination import SyncCursorPage, AsyncCursorPage @@ -23,30 +24,22 @@ class TestMachines: @parametrize def test_method_create(self, client: Dedalus) -> None: - machine = client.machines.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) + machine = client.machines.create() assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Dedalus) -> None: machine = client.machines.create( - memory_mib=0, - storage_gib=0, - vcpu=0, autosleep="autosleep", + memory_mib=1, + storage_gib=1, + vcpu=1, ) assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_raw_response_create(self, client: Dedalus) -> None: - response = client.machines.with_raw_response.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) + response = client.machines.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -55,11 +48,7 @@ def test_raw_response_create(self, client: Dedalus) -> None: @parametrize def test_streaming_response_create(self, client: Dedalus) -> None: - with client.machines.with_streaming_response.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) as response: + with client.machines.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -71,31 +60,31 @@ def test_streaming_response_create(self, client: Dedalus) -> None: @parametrize def test_method_retrieve(self, client: Dedalus) -> None: machine = client.machines.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: Dedalus) -> None: response = client.machines.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" machine = response.parse() - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) @parametrize def test_streaming_response_retrieve(self, client: Dedalus) -> None: with client.machines.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" machine = response.parse() - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) assert cast(Any, response.is_closed) is True @@ -109,14 +98,14 @@ def test_path_params_retrieve(self, client: Dedalus) -> None: @parametrize def test_method_update(self, client: Dedalus) -> None: machine = client.machines.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_method_update_with_all_params(self, client: Dedalus) -> None: machine = client.machines.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", autosleep="autosleep", memory_mib=0, storage_gib=0, @@ -127,7 +116,7 @@ def test_method_update_with_all_params(self, client: Dedalus) -> None: @parametrize def test_raw_response_update(self, client: Dedalus) -> None: response = client.machines.with_raw_response.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -138,7 +127,7 @@ def test_raw_response_update(self, client: Dedalus) -> None: @parametrize def test_streaming_response_update(self, client: Dedalus) -> None: with client.machines.with_streaming_response.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -191,14 +180,14 @@ def test_streaming_response_list(self, client: Dedalus) -> None: @parametrize def test_method_delete(self, client: Dedalus) -> None: machine = client.machines.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_raw_response_delete(self, client: Dedalus) -> None: response = client.machines.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -209,7 +198,7 @@ def test_raw_response_delete(self, client: Dedalus) -> None: @parametrize def test_streaming_response_delete(self, client: Dedalus) -> None: with client.machines.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -229,14 +218,14 @@ def test_path_params_delete(self, client: Dedalus) -> None: @parametrize def test_method_sleep(self, client: Dedalus) -> None: machine = client.machines.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_raw_response_sleep(self, client: Dedalus) -> None: response = client.machines.with_raw_response.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -247,7 +236,7 @@ def test_raw_response_sleep(self, client: Dedalus) -> None: @parametrize def test_streaming_response_sleep(self, client: Dedalus) -> None: with client.machines.with_streaming_response.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -267,14 +256,14 @@ def test_path_params_sleep(self, client: Dedalus) -> None: @parametrize def test_method_wake(self, client: Dedalus) -> None: machine = client.machines.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize def test_raw_response_wake(self, client: Dedalus) -> None: response = client.machines.with_raw_response.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -285,7 +274,7 @@ def test_raw_response_wake(self, client: Dedalus) -> None: @parametrize def test_streaming_response_wake(self, client: Dedalus) -> None: with client.machines.with_streaming_response.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -302,51 +291,6 @@ def test_path_params_wake(self, client: Dedalus) -> None: machine_id="", ) - @parametrize - def test_method_watch(self, client: Dedalus) -> None: - machine_stream = client.machines.watch( - machine_id="dm-3", - ) - machine_stream.response.close() - - @parametrize - def test_method_watch_with_all_params(self, client: Dedalus) -> None: - machine_stream = client.machines.watch( - machine_id="dm-3", - last_event_id="Last-Event-ID", - ) - machine_stream.response.close() - - @parametrize - def test_raw_response_watch(self, client: Dedalus) -> None: - response = client.machines.with_raw_response.watch( - machine_id="dm-3", - ) - - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = response.parse() - stream.close() - - @parametrize - def test_streaming_response_watch(self, client: Dedalus) -> None: - with client.machines.with_streaming_response.watch( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = response.parse() - stream.close() - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_watch(self, client: Dedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - client.machines.with_raw_response.watch( - machine_id="", - ) - class TestAsyncMachines: parametrize = pytest.mark.parametrize( @@ -355,30 +299,22 @@ class TestAsyncMachines: @parametrize async def test_method_create(self, async_client: AsyncDedalus) -> None: - machine = await async_client.machines.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) + machine = await async_client.machines.create() assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.create( - memory_mib=0, - storage_gib=0, - vcpu=0, autosleep="autosleep", + memory_mib=1, + storage_gib=1, + vcpu=1, ) assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.with_raw_response.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) + response = await async_client.machines.with_raw_response.create() assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -387,11 +323,7 @@ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.with_streaming_response.create( - memory_mib=0, - storage_gib=0, - vcpu=0, - ) as response: + async with async_client.machines.with_streaming_response.create() as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -403,31 +335,31 @@ async def test_streaming_response_create(self, async_client: AsyncDedalus) -> No @parametrize async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.with_raw_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" machine = await response.parse() - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: async with async_client.machines.with_streaming_response.retrieve( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" machine = await response.parse() - assert_matches_type(Machine, machine, path=["response"]) + assert_matches_type(MachineRetrieveResponse, machine, path=["response"]) assert cast(Any, response.is_closed) is True @@ -441,14 +373,14 @@ async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_update(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_method_update_with_all_params(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", autosleep="autosleep", memory_mib=0, storage_gib=0, @@ -459,7 +391,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncDedalus) - @parametrize async def test_raw_response_update(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.with_raw_response.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -470,7 +402,7 @@ async def test_raw_response_update(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_update(self, async_client: AsyncDedalus) -> None: async with async_client.machines.with_streaming_response.update( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -523,14 +455,14 @@ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None @parametrize async def test_method_delete(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.with_raw_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -541,7 +473,7 @@ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None: async with async_client.machines.with_streaming_response.delete( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -561,14 +493,14 @@ async def test_path_params_delete(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_sleep(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_raw_response_sleep(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.with_raw_response.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -579,7 +511,7 @@ async def test_raw_response_sleep(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_sleep(self, async_client: AsyncDedalus) -> None: async with async_client.machines.with_streaming_response.sleep( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -599,14 +531,14 @@ async def test_path_params_sleep(self, async_client: AsyncDedalus) -> None: @parametrize async def test_method_wake(self, async_client: AsyncDedalus) -> None: machine = await async_client.machines.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert_matches_type(Machine, machine, path=["response"]) @parametrize async def test_raw_response_wake(self, async_client: AsyncDedalus) -> None: response = await async_client.machines.with_raw_response.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) assert response.is_closed is True @@ -617,7 +549,7 @@ async def test_raw_response_wake(self, async_client: AsyncDedalus) -> None: @parametrize async def test_streaming_response_wake(self, async_client: AsyncDedalus) -> None: async with async_client.machines.with_streaming_response.wake( - machine_id="dm-3", + machine_id="dm-ecc2efdd-ddfa-31a9-c6f1-b833d337aa7c", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -633,48 +565,3 @@ async def test_path_params_wake(self, async_client: AsyncDedalus) -> None: await async_client.machines.with_raw_response.wake( machine_id="", ) - - @parametrize - async def test_method_watch(self, async_client: AsyncDedalus) -> None: - machine_stream = await async_client.machines.watch( - machine_id="dm-3", - ) - await machine_stream.response.aclose() - - @parametrize - async def test_method_watch_with_all_params(self, async_client: AsyncDedalus) -> None: - machine_stream = await async_client.machines.watch( - machine_id="dm-3", - last_event_id="Last-Event-ID", - ) - await machine_stream.response.aclose() - - @parametrize - async def test_raw_response_watch(self, async_client: AsyncDedalus) -> None: - response = await async_client.machines.with_raw_response.watch( - machine_id="dm-3", - ) - - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - stream = await response.parse() - await stream.close() - - @parametrize - async def test_streaming_response_watch(self, async_client: AsyncDedalus) -> None: - async with async_client.machines.with_streaming_response.watch( - machine_id="dm-3", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - stream = await response.parse() - await stream.close() - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_watch(self, async_client: AsyncDedalus) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `machine_id` but received ''"): - await async_client.machines.with_raw_response.watch( - machine_id="", - ) diff --git a/tests/api_resources/test_usage.py b/tests/api_resources/test_usage.py deleted file mode 100644 index ca8aa7e..0000000 --- a/tests/api_resources/test_usage.py +++ /dev/null @@ -1,230 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from dedalus_sdk import Dedalus, AsyncDedalus -from tests.utils import assert_matches_type -from dedalus_sdk.types import ( - OrgUsage, - MachineComputeUsage, - MachineStorageUsage, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestUsage: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Dedalus) -> None: - usage = client.usage.retrieve() - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Dedalus) -> None: - usage = client.usage.retrieve( - period_start="period_start", - ) - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Dedalus) -> None: - response = client.usage.with_raw_response.retrieve() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Dedalus) -> None: - with client.usage.with_streaming_response.retrieve() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(OrgUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_machine_compute(self, client: Dedalus) -> None: - usage = client.usage.machine_compute() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - def test_method_machine_compute_with_all_params(self, client: Dedalus) -> None: - usage = client.usage.machine_compute( - granularity="granularity", - machine_id="machine_id", - period_end="period_end", - period_start="period_start", - ) - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - def test_raw_response_machine_compute(self, client: Dedalus) -> None: - response = client.usage.with_raw_response.machine_compute() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - def test_streaming_response_machine_compute(self, client: Dedalus) -> None: - with client.usage.with_streaming_response.machine_compute() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_machine_storage(self, client: Dedalus) -> None: - usage = client.usage.machine_storage() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - def test_method_machine_storage_with_all_params(self, client: Dedalus) -> None: - usage = client.usage.machine_storage( - machine_id="machine_id", - period_end="period_end", - period_start="period_start", - ) - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - def test_raw_response_machine_storage(self, client: Dedalus) -> None: - response = client.usage.with_raw_response.machine_storage() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - def test_streaming_response_machine_storage(self, client: Dedalus) -> None: - with client.usage.with_streaming_response.machine_storage() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncUsage: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.retrieve() - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.retrieve( - period_start="period_start", - ) - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None: - response = await async_client.usage.with_raw_response.retrieve() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(OrgUsage, usage, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None: - async with async_client.usage.with_streaming_response.retrieve() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(OrgUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_machine_compute(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.machine_compute() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - async def test_method_machine_compute_with_all_params(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.machine_compute( - granularity="granularity", - machine_id="machine_id", - period_end="period_end", - period_start="period_start", - ) - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - async def test_raw_response_machine_compute(self, async_client: AsyncDedalus) -> None: - response = await async_client.usage.with_raw_response.machine_compute() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - @parametrize - async def test_streaming_response_machine_compute(self, async_client: AsyncDedalus) -> None: - async with async_client.usage.with_streaming_response.machine_compute() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(MachineComputeUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_machine_storage(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.machine_storage() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - async def test_method_machine_storage_with_all_params(self, async_client: AsyncDedalus) -> None: - usage = await async_client.usage.machine_storage( - machine_id="machine_id", - period_end="period_end", - period_start="period_start", - ) - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - async def test_raw_response_machine_storage(self, async_client: AsyncDedalus) -> None: - response = await async_client.usage.with_raw_response.machine_storage() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - @parametrize - async def test_streaming_response_machine_storage(self, async_client: AsyncDedalus) -> None: - async with async_client.usage.with_streaming_response.machine_storage() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(MachineStorageUsage, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/test_client.py b/tests/test_client.py index 63f5c33..c230dbd 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -23,7 +23,6 @@ from dedalus_sdk._types import Omit from dedalus_sdk._utils import asyncify from dedalus_sdk._models import BaseModel, FinalRequestOptions -from dedalus_sdk._streaming import Stream, AsyncStream from dedalus_sdk._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError from dedalus_sdk._base_client import ( DEFAULT_TIMEOUT, @@ -861,17 +860,6 @@ def test_client_max_retries_validation(self) -> None: with pytest.raises(TypeError, match=r"max_retries cannot be None"): Dedalus(base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None)) - @pytest.mark.respx(base_url=base_url) - def test_default_stream_cls(self, respx_mock: MockRouter, client: Dedalus) -> None: - class Model(BaseModel): - name: str - - respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - stream = client.post("/foo", cast_to=Model, stream=True, stream_cls=Stream[Model]) - assert isinstance(stream, Stream) - stream.response.close() - @pytest.mark.respx(base_url=base_url) def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): @@ -928,7 +916,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien respx_mock.post("/v1/machines").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - client.machines.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__enter__() + client.machines.with_streaming_response.create().__enter__() assert _get_open_connections(client) == 0 @@ -938,7 +926,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client respx_mock.post("/v1/machines").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - client.machines.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__enter__() + client.machines.with_streaming_response.create().__enter__() assert _get_open_connections(client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -967,7 +955,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = client.machines.with_raw_response.create(memory_mib=0, storage_gib=0, vcpu=0) + response = client.machines.with_raw_response.create() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -991,9 +979,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = client.machines.with_raw_response.create( - memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": Omit()} - ) + response = client.machines.with_raw_response.create(extra_headers={"x-stainless-retry-count": Omit()}) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -1016,9 +1002,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = client.machines.with_raw_response.create( - memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": "42"} - ) + response = client.machines.with_raw_response.create(extra_headers={"x-stainless-retry-count": "42"}) assert response.http_request.headers.get("x-stainless-retry-count") == "42" @@ -1846,17 +1830,6 @@ async def test_client_max_retries_validation(self) -> None: base_url=base_url, api_key=api_key, _strict_response_validation=True, max_retries=cast(Any, None) ) - @pytest.mark.respx(base_url=base_url) - async def test_default_stream_cls(self, respx_mock: MockRouter, async_client: AsyncDedalus) -> None: - class Model(BaseModel): - name: str - - respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - stream = await async_client.post("/foo", cast_to=Model, stream=True, stream_cls=AsyncStream[Model]) - assert isinstance(stream, AsyncStream) - await stream.response.aclose() - @pytest.mark.respx(base_url=base_url) async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): @@ -1915,7 +1888,7 @@ async def test_retrying_timeout_errors_doesnt_leak( respx_mock.post("/v1/machines").mock(side_effect=httpx.TimeoutException("Test timeout error")) with pytest.raises(APITimeoutError): - await async_client.machines.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__aenter__() + await async_client.machines.with_streaming_response.create().__aenter__() assert _get_open_connections(async_client) == 0 @@ -1925,7 +1898,7 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, respx_mock.post("/v1/machines").mock(return_value=httpx.Response(500)) with pytest.raises(APIStatusError): - await async_client.machines.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__aenter__() + await async_client.machines.with_streaming_response.create().__aenter__() assert _get_open_connections(async_client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @@ -1954,7 +1927,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = await client.machines.with_raw_response.create(memory_mib=0, storage_gib=0, vcpu=0) + response = await client.machines.with_raw_response.create() assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success @@ -1978,9 +1951,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = await client.machines.with_raw_response.create( - memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": Omit()} - ) + response = await client.machines.with_raw_response.create(extra_headers={"x-stainless-retry-count": Omit()}) assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 @@ -2003,9 +1974,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: respx_mock.post("/v1/machines").mock(side_effect=retry_handler) - response = await client.machines.with_raw_response.create( - memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": "42"} - ) + response = await client.machines.with_raw_response.create(extra_headers={"x-stainless-retry-count": "42"}) assert response.http_request.headers.get("x-stainless-retry-count") == "42" diff --git a/tests/test_send_queue.py b/tests/test_send_queue.py deleted file mode 100644 index 196d78d..0000000 --- a/tests/test_send_queue.py +++ /dev/null @@ -1,128 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import pytest - -from dedalus_sdk._exceptions import WebSocketQueueFullError -from dedalus_sdk._send_queue import SendQueue - - -class TestSendQueue: - def test_enqueue_and_drain(self) -> None: - q = SendQueue() - q.enqueue('{"type": "session.update"}') - q.enqueue('{"type": "response.create"}') - assert len(q) == 2 - - items = q.drain() - assert items == ['{"type": "session.update"}', '{"type": "response.create"}'] - assert len(q) == 0 - - def test_enqueue_respects_byte_limit(self) -> None: - q = SendQueue(max_bytes=10) - q.enqueue("12345") # 5 bytes, fits - with pytest.raises(WebSocketQueueFullError): - q.enqueue("123456") # 6 bytes, would exceed 10 - assert len(q) == 1 - - def test_drain_empties_queue(self) -> None: - q = SendQueue() - q.enqueue("hello") - q.drain() - assert len(q) == 0 - assert not q - - def test_bool(self) -> None: - q = SendQueue() - assert not q - q.enqueue("x") - assert q - - def test_flush_sync(self) -> None: - q = SendQueue() - q.enqueue("a") - q.enqueue("b") - q.enqueue("c") - - sent: list[str] = [] - q.flush_sync(sent.append) - assert sent == ["a", "b", "c"] - assert len(q) == 0 - - def test_flush_sync_requeues_on_failure(self) -> None: - q = SendQueue() - q.enqueue("a") - q.enqueue("b") - q.enqueue("c") - - sent: list[str] = [] - - def failing_send(data: str) -> None: - if data == "b": - raise RuntimeError("send failed") - sent.append(data) - - with pytest.raises(RuntimeError, match="send failed"): - q.flush_sync(failing_send) - - assert sent == ["a"] - # b and c should be re-queued - remaining = q.drain() - assert remaining == ["b", "c"] - - @pytest.mark.asyncio - async def test_flush_async(self) -> None: - q = SendQueue() - q.enqueue("a") - q.enqueue("b") - - sent: list[str] = [] - - async def async_send(data: str) -> None: - sent.append(data) - - await q.flush_async(async_send) - assert sent == ["a", "b"] - assert len(q) == 0 - - @pytest.mark.asyncio - async def test_flush_async_requeues_on_failure(self) -> None: - q = SendQueue() - q.enqueue("a") - q.enqueue("b") - q.enqueue("c") - - sent: list[str] = [] - - async def failing_send(data: str) -> None: - if data == "b": - raise RuntimeError("send failed") - sent.append(data) - - with pytest.raises(RuntimeError, match="send failed"): - await q.flush_async(failing_send) - - assert sent == ["a"] - remaining = q.drain() - assert remaining == ["b", "c"] - - def test_flush_sync_preserves_new_items_on_failure(self) -> None: - """If items are enqueued after flush starts and flush fails, - the re-queued items should come before the new items.""" - q = SendQueue() - q.enqueue("a") - q.enqueue("b") - - def failing_send(data: str) -> None: - if data == "b": - # Simulate another thread enqueuing during flush - q.enqueue("new") - raise RuntimeError("fail") - - with pytest.raises(RuntimeError): - q.flush_sync(failing_send) - - # "b" (failed) should come before "new" (added during flush) - remaining = q.drain() - assert remaining == ["b", "new"] diff --git a/uv.lock b/uv.lock index c06f3a3..2facb36 100644 --- a/uv.lock +++ b/uv.lock @@ -261,9 +261,6 @@ aiohttp = [ { name = "aiohttp" }, { name = "httpx-aiohttp" }, ] -websockets = [ - { name = "websockets" }, -] [package.dev-dependencies] dev = [ @@ -299,9 +296,8 @@ requires-dist = [ { name = "pydantic", specifier = ">=1.9.0,<3" }, { name = "sniffio" }, { name = "typing-extensions", specifier = ">=4.14,<5" }, - { name = "websockets", marker = "extra == 'websockets'", specifier = ">=13,<16" }, ] -provides-extras = ["aiohttp", "websockets"] +provides-extras = ["aiohttp"] [package.metadata.requires-dev] dev = [ @@ -1681,82 +1677,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/36/db/3fff0bcbe339a6fa6a3b9e3fbc2bfb321ec2f4cd233692272c5a8d6cf801/websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5", size = 175424, upload-time = "2025-03-05T20:02:56.505Z" }, - { url = "https://files.pythonhosted.org/packages/46/e6/519054c2f477def4165b0ec060ad664ed174e140b0d1cbb9fafa4a54f6db/websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a", size = 173077, upload-time = "2025-03-05T20:02:58.37Z" }, - { url = "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b", size = 173324, upload-time = "2025-03-05T20:02:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/1c/cb/51ba82e59b3a664df54beed8ad95517c1b4dc1a913730e7a7db778f21291/websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770", size = 182094, upload-time = "2025-03-05T20:03:01.827Z" }, - { url = "https://files.pythonhosted.org/packages/fb/0f/bf3788c03fec679bcdaef787518dbe60d12fe5615a544a6d4cf82f045193/websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb", size = 181094, upload-time = "2025-03-05T20:03:03.123Z" }, - { url = "https://files.pythonhosted.org/packages/5e/da/9fb8c21edbc719b66763a571afbaf206cb6d3736d28255a46fc2fe20f902/websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054", size = 181397, upload-time = "2025-03-05T20:03:04.443Z" }, - { url = "https://files.pythonhosted.org/packages/2e/65/65f379525a2719e91d9d90c38fe8b8bc62bd3c702ac651b7278609b696c4/websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee", size = 181794, upload-time = "2025-03-05T20:03:06.708Z" }, - { url = "https://files.pythonhosted.org/packages/d9/26/31ac2d08f8e9304d81a1a7ed2851c0300f636019a57cbaa91342015c72cc/websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed", size = 181194, upload-time = "2025-03-05T20:03:08.844Z" }, - { url = "https://files.pythonhosted.org/packages/98/72/1090de20d6c91994cd4b357c3f75a4f25ee231b63e03adea89671cc12a3f/websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880", size = 181164, upload-time = "2025-03-05T20:03:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/2d/37/098f2e1c103ae8ed79b0e77f08d83b0ec0b241cf4b7f2f10edd0126472e1/websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411", size = 176381, upload-time = "2025-03-05T20:03:12.77Z" }, - { url = "https://files.pythonhosted.org/packages/75/8b/a32978a3ab42cebb2ebdd5b05df0696a09f4d436ce69def11893afa301f0/websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4", size = 176841, upload-time = "2025-03-05T20:03:14.367Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/b7/48/4b67623bac4d79beb3a6bb27b803ba75c1bdedc06bd827e465803690a4b2/websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940", size = 173106, upload-time = "2025-03-05T20:03:29.404Z" }, - { url = "https://files.pythonhosted.org/packages/ed/f0/adb07514a49fe5728192764e04295be78859e4a537ab8fcc518a3dbb3281/websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e", size = 173339, upload-time = "2025-03-05T20:03:30.755Z" }, - { url = "https://files.pythonhosted.org/packages/87/28/bd23c6344b18fb43df40d0700f6d3fffcd7cef14a6995b4f976978b52e62/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9", size = 174597, upload-time = "2025-03-05T20:03:32.247Z" }, - { url = "https://files.pythonhosted.org/packages/6d/79/ca288495863d0f23a60f546f0905ae8f3ed467ad87f8b6aceb65f4c013e4/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b", size = 174205, upload-time = "2025-03-05T20:03:33.731Z" }, - { url = "https://files.pythonhosted.org/packages/04/e4/120ff3180b0872b1fe6637f6f995bcb009fb5c87d597c1fc21456f50c848/websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f", size = 174150, upload-time = "2025-03-05T20:03:35.757Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c3/30e2f9c539b8da8b1d76f64012f3b19253271a63413b2d3adb94b143407f/websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123", size = 176877, upload-time = "2025-03-05T20:03:37.199Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - [[package]] name = "yarl" version = "1.22.0"