diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..0dd0347
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,4 @@
+# This file is used to automatically assign reviewers to PRs
+# For more information see: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
+
+* @windsornguyen
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8b76e3c..077a972 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,12 +1,14 @@
name: CI
on:
push:
- branches-ignore:
- - 'generated'
- - 'codegen/**'
- - 'integrated/**'
- - 'stl-preview-head/**'
- - 'stl-preview-base/**'
+ branches:
+ - '**'
+ - '!integrated/**'
+ - '!stl-preview-head/**'
+ - '!stl-preview-base/**'
+ - '!generated'
+ - '!codegen/**'
+ - 'codegen/stl/**'
pull_request:
branches-ignore:
- 'stl-preview-head/**'
@@ -55,14 +57,18 @@ jobs:
run: uv build
- name: Get GitHub OIDC Token
- if: github.repository == 'stainless-sdks/dedalus-python'
+ if: |-
+ github.repository == 'stainless-sdks/dedalus-python' &&
+ !startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());
- name: Upload tarball
- if: github.repository == 'stainless-sdks/dedalus-python'
+ if: |-
+ github.repository == 'stainless-sdks/dedalus-python' &&
+ !startsWith(github.ref, 'refs/heads/stl/')
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml
new file mode 100644
index 0000000..7e1e57e
--- /dev/null
+++ b/.github/workflows/publish-pypi.yml
@@ -0,0 +1,30 @@
+# This workflow is triggered when a GitHub release is created.
+# It can also be run manually to re-publish to PyPI in case it failed for some reason.
+# You can run this workflow by navigating to https://www.github.com/dedalus-labs/dedalus-python/actions/workflows/publish-pypi.yml
+name: Publish PyPI
+on:
+ workflow_dispatch:
+
+ release:
+ types: [published]
+
+jobs:
+ publish:
+ name: publish
+ runs-on: ubuntu-latest
+ environment: production
+ permissions:
+ contents: read
+ id-token: write
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Install uv
+ uses: astral-sh/setup-uv@v5
+ with:
+ version: '0.9.13'
+
+ - name: Publish to PyPI
+ run: |
+ bash ./bin/publish-pypi
diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml
new file mode 100644
index 0000000..07a625c
--- /dev/null
+++ b/.github/workflows/release-doctor.yml
@@ -0,0 +1,20 @@
+name: Release Doctor
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch:
+
+jobs:
+ release_doctor:
+ name: release doctor
+ runs-on: ubuntu-latest
+ environment: production
+ if: github.repository == 'dedalus-labs/dedalus-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Check release environment
+ run: |
+ bash ./bin/check-release-environment
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
new file mode 100644
index 0000000..1332969
--- /dev/null
+++ b/.release-please-manifest.json
@@ -0,0 +1,3 @@
+{
+ ".": "0.0.1"
+}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index ff92891..bd8a834 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 19
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs%2Fdedalus-6937085190e3e5553f943ff22deda900cd8ad4bf5e37278cba7de683b78ae8d2.yml
-openapi_spec_hash: 85dc5d1e011be6539c240594f06f284b
-config_hash: cf68758556373bda769f95986190194b
+configured_endpoints: 26
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs%2Fdedalus-8209ddf6d2b12680c9d569e68ad89c347a59dcad5de4b2e5144ab9e2d6a41cbf.yml
+openapi_spec_hash: 220a31347115af6017c6d2e7555343c3
+config_hash: 1b4ea4f6d19e650bbc797440435befc4
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..2667c57
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,32 @@
+# Changelog
+
+## 0.0.1 (2026-03-18)
+
+Full Changelog: [v0.0.1...v0.0.1](https://github.com/dedalus-labs/dedalus-python/compare/v0.0.1...v0.0.1)
+
+### Features
+
+* **api:** stable beta ([e6391a9](https://github.com/dedalus-labs/dedalus-python/commit/e6391a959ccc51ad1f9c5072e2190ea7bfb5a94a))
+
+
+### Bug Fixes
+
+* **api:** update flags ([21bb2b7](https://github.com/dedalus-labs/dedalus-python/commit/21bb2b79a38d89d4cd092ab2d3f6a70800fbc679))
+* **deps:** bump minimum typing-extensions version ([7016283](https://github.com/dedalus-labs/dedalus-python/commit/7016283a4a8b4278321f56b30fec1d5b39bda19e))
+* **pydantic:** do not pass `by_alias` unless set ([113574f](https://github.com/dedalus-labs/dedalus-python/commit/113574f4a1f50ea676188724b48497b5491afb5d))
+
+
+### Chores
+
+* **api:** resolving merge conflicts ([706fa9e](https://github.com/dedalus-labs/dedalus-python/commit/706fa9e077164a8e7a4159e5aa536434ac7e6550))
+* **ci:** skip uploading artifacts on stainless-internal branches ([972c929](https://github.com/dedalus-labs/dedalus-python/commit/972c929aef5d5a2bbd8f6b5b0a2ec3d4902dd3b7))
+* configure new SDK language ([15fc048](https://github.com/dedalus-labs/dedalus-python/commit/15fc048d78b703a0a1e3e3b763f6890bdefa2e19))
+* **internal:** tweak CI branches ([c8ce919](https://github.com/dedalus-labs/dedalus-python/commit/c8ce919b2190e19a9b429494b1016490acae315d))
+* update placeholder string ([b8e57a4](https://github.com/dedalus-labs/dedalus-python/commit/b8e57a48d562d50b003121ffe8ecb3bfe9182035))
+* update SDK settings ([01a998a](https://github.com/dedalus-labs/dedalus-python/commit/01a998a38e06160aed0acfb53a6b13388fc64761))
+* update SDK settings ([b7e80bb](https://github.com/dedalus-labs/dedalus-python/commit/b7e80bb8af98797576d31f5b218fdd2bdf417cd7))
+* update SDK settings ([4ceefe7](https://github.com/dedalus-labs/dedalus-python/commit/4ceefe72c5a920b2a83924bfd662cff81c260f42))
+* update SDK settings ([00d1f1a](https://github.com/dedalus-labs/dedalus-python/commit/00d1f1ab5a81bbf4bbe076de7261311f351ee477))
+* update SDK settings ([2240862](https://github.com/dedalus-labs/dedalus-python/commit/22408628cfde349577c7830b4fb2326e91f43444))
+* update SDK settings ([9580045](https://github.com/dedalus-labs/dedalus-python/commit/958004593a4a1369dd7983af2591ac5e0ca655af))
+* update SDK settings ([f9cd760](https://github.com/dedalus-labs/dedalus-python/commit/f9cd760421fd8d06c920e23c12e9c289dab2d81a))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c4eeefc..5794a3b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,7 +36,7 @@ $ pip install -r requirements-dev.lock
Most of the SDK is generated code. Modifications to code will be persisted between generations, but may
result in merge conflicts between manual patches and changes from the generator. The generator will never
-modify the contents of the `src/dedalus/lib/` and `examples/` directories.
+modify the contents of the `src/dedalus_sdk/lib/` and `examples/` directories.
## Adding and running examples
@@ -62,7 +62,7 @@ If you’d like to use the repository from source, you can either install from g
To install via git:
```sh
-$ pip install git+ssh://git@github.com/stainless-sdks/dedalus-python.git
+$ pip install git+ssh://git@github.com/dedalus-labs/dedalus-python.git
```
Alternatively, you can build from source and install the wheel file:
@@ -85,6 +85,12 @@ $ pip install ./path-to-wheel-file.whl
## Running tests
+Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
+
+```sh
+$ ./scripts/mock
+```
+
```sh
$ ./scripts/test
```
@@ -113,7 +119,7 @@ the changes aren't made through the automated pipeline, you may want to make rel
### Publish with a GitHub workflow
-You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/stainless-sdks/dedalus-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up.
+You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/dedalus-labs/dedalus-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up.
### Publish manually
diff --git a/LICENSE b/LICENSE
index d6e38b3..3aa6139 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,201 +1,7 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
+Copyright 2026 Dedalus
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- 1. Definitions.
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2026 Dedalus
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 2933a7f..2abfa3d 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Dedalus Python API library
-[)](https://pypi.org/project/dedalus/)
+[)](https://pypi.org/project/dedalus-sdk/)
The Dedalus Python library provides convenient access to the Dedalus REST API from any Python 3.9+
application. The library includes type definitions for all request params and response fields,
@@ -13,49 +13,46 @@ It is generated with [Stainless](https://www.stainless.com/).
Use the Dedalus MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.
-[](https://cursor.com/en-US/install-mcp?name=dedalus-mcp&config=eyJuYW1lIjoiZGVkYWx1cy1tY3AiLCJ0cmFuc3BvcnQiOiJodHRwIiwidXJsIjoiaHR0cHM6Ly9kZWRhbHVzLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7ImFwaV9rZXkiOiJNeSBBUEkgS2V5In19)
-[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22dedalus-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fdedalus.stlmcp.com%22%2C%22headers%22%3A%7B%22api_key%22%3A%22My%20API%20Key%22%7D%7D)
+[](https://cursor.com/en-US/install-mcp?name=dedalus-mcp&config=eyJuYW1lIjoiZGVkYWx1cy1tY3AiLCJ0cmFuc3BvcnQiOiJodHRwIiwidXJsIjoiaHR0cHM6Ly9kZWRhbHVzLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7IngtYXBpLWtleSI6Ik15IFggQVBJIEtleSIsIngtZGVkYWx1cy1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)
+[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22dedalus-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fdedalus.stlmcp.com%22%2C%22headers%22%3A%7B%22x-api-key%22%3A%22My%20X%20API%20Key%22%2C%22x-dedalus-api-key%22%3A%22My%20API%20Key%22%7D%7D)
> Note: You may need to set environment variables in your MCP client.
## Documentation
-The full API of this library can be found in [api.md](api.md).
+The REST API documentation can be found on [docs.dedaluslabs.ai](https://docs.dedaluslabs.ai). The full API of this library can be found in [api.md](api.md).
## Installation
```sh
-# install from this staging repo
-pip install git+ssh://git@github.com/stainless-sdks/dedalus-python.git
+# install from PyPI
+pip install dedalus-sdk
```
-> [!NOTE]
-> Once this package is [published to PyPI](https://www.stainless.com/docs/guides/publish), this will become: `pip install dedalus`
-
## Usage
The full API of this library can be found in [api.md](api.md).
```python
import os
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
client = Dedalus(
- api_key=os.environ.get("PETSTORE_API_KEY"), # This is the default and can be omitted
+ api_key=os.environ.get("DEDALUS_API_KEY"), # This is the default and can be omitted
)
-order = client.store.orders.create(
- pet_id=1,
- quantity=1,
- status="placed",
+workspace = client.workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
)
-print(order.id)
+print(workspace.workspace_id)
```
-While you can provide an `api_key` keyword argument,
+While you can provide a `x_api_key` keyword argument,
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
-to add `PETSTORE_API_KEY="My API Key"` to your `.env` file
-so that your API Key is not stored in source control.
+to add `DEDALUS_X_API_KEY="My X API Key"` to your `.env` file
+so that your X API Key is not stored in source control.
## Async usage
@@ -64,20 +61,20 @@ Simply import `AsyncDedalus` instead of `Dedalus` and use `await` with each API
```python
import os
import asyncio
-from dedalus import AsyncDedalus
+from dedalus_sdk import AsyncDedalus
client = AsyncDedalus(
- api_key=os.environ.get("PETSTORE_API_KEY"), # This is the default and can be omitted
+ api_key=os.environ.get("DEDALUS_API_KEY"), # This is the default and can be omitted
)
async def main() -> None:
- order = await client.store.orders.create(
- pet_id=1,
- quantity=1,
- status="placed",
+ workspace = await client.workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
)
- print(order.id)
+ print(workspace.workspace_id)
asyncio.run(main())
@@ -92,8 +89,8 @@ By default, the async client uses `httpx` for HTTP requests. However, for improv
You can enable this by installing `aiohttp`:
```sh
-# install from this staging repo
-pip install 'dedalus[aiohttp] @ git+ssh://git@github.com/stainless-sdks/dedalus-python.git'
+# install from PyPI
+pip install dedalus-sdk[aiohttp]
```
Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:
@@ -101,21 +98,21 @@ Then you can enable it by instantiating the client with `http_client=DefaultAioH
```python
import os
import asyncio
-from dedalus import DefaultAioHttpClient
-from dedalus import AsyncDedalus
+from dedalus_sdk import DefaultAioHttpClient
+from dedalus_sdk import AsyncDedalus
async def main() -> None:
async with AsyncDedalus(
- api_key=os.environ.get("PETSTORE_API_KEY"), # This is the default and can be omitted
+ api_key=os.environ.get("DEDALUS_API_KEY"), # This is the default and can be omitted
http_client=DefaultAioHttpClient(),
) as client:
- order = await client.store.orders.create(
- pet_id=1,
- quantity=1,
- status="placed",
+ workspace = await client.workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
)
- print(order.id)
+ print(workspace.workspace_id)
asyncio.run(main())
@@ -130,46 +127,96 @@ Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typ
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.
-## Nested params
+## Pagination
-Nested parameters are dictionaries, typed using `TypedDict`, for example:
+List methods in the Dedalus API are paginated.
+
+This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:
```python
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
client = Dedalus()
-pet = client.pets.create(
- name="doggie",
- photo_urls=["string"],
- category={},
-)
-print(pet.category)
+all_workspaces = []
+# Automatically fetches more pages as needed.
+for workspace in client.workspaces.list():
+ # Do something with workspace here
+ all_workspaces.append(workspace)
+print(all_workspaces)
+```
+
+Or, asynchronously:
+
+```python
+import asyncio
+from dedalus_sdk import AsyncDedalus
+
+client = AsyncDedalus()
+
+
+async def main() -> None:
+ all_workspaces = []
+ # Iterate through items across all pages, issuing requests as needed.
+ async for workspace in client.workspaces.list():
+ all_workspaces.append(workspace)
+ print(all_workspaces)
+
+
+asyncio.run(main())
+```
+
+Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:
+
+```python
+first_page = await client.workspaces.list()
+if first_page.has_next_page():
+ print(f"will fetch next page using these details: {first_page.next_page_info()}")
+ next_page = await first_page.get_next_page()
+ print(f"number of items we just fetched: {len(next_page.items)}")
+
+# Remove `await` for non-async usage.
+```
+
+Or just work directly with the returned data:
+
+```python
+first_page = await client.workspaces.list()
+
+print(f"next page cursor: {first_page.next_cursor}") # => "next page cursor: ..."
+for workspace in first_page.items:
+ print(workspace.workspace_id)
+
+# Remove `await` for non-async usage.
```
## Handling errors
-When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `dedalus.APIConnectionError` is raised.
+When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `dedalus_sdk.APIConnectionError` is raised.
When the API returns a non-success status code (that is, 4xx or 5xx
-response), a subclass of `dedalus.APIStatusError` is raised, containing `status_code` and `response` properties.
+response), a subclass of `dedalus_sdk.APIStatusError` is raised, containing `status_code` and `response` properties.
-All errors inherit from `dedalus.APIError`.
+All errors inherit from `dedalus_sdk.APIError`.
```python
-import dedalus
-from dedalus import Dedalus
+import dedalus_sdk
+from dedalus_sdk import Dedalus
client = Dedalus()
try:
- client.store.list_inventory()
-except dedalus.APIConnectionError as e:
+ client.workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
+ )
+except dedalus_sdk.APIConnectionError as e:
print("The server could not be reached")
print(e.__cause__) # an underlying Exception, likely raised within httpx.
-except dedalus.RateLimitError as e:
+except dedalus_sdk.RateLimitError as e:
print("A 429 status code was received; we should back off a bit.")
-except dedalus.APIStatusError as e:
+except dedalus_sdk.APIStatusError as e:
print("Another non-200-range status code was received")
print(e.status_code)
print(e.response)
@@ -197,7 +244,7 @@ Connection errors (for example, due to a network connectivity problem), 408 Requ
You can use the `max_retries` option to configure or disable retry settings:
```python
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
# Configure the default for all requests:
client = Dedalus(
@@ -206,7 +253,11 @@ client = Dedalus(
)
# Or, configure per-request:
-client.with_options(max_retries=5).store.list_inventory()
+client.with_options(max_retries=5).workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
+)
```
### Timeouts
@@ -215,7 +266,7 @@ By default requests time out after 1 minute. You can configure this with a `time
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:
```python
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
# Configure the default for all requests:
client = Dedalus(
@@ -229,7 +280,11 @@ client = Dedalus(
)
# Override per-request:
-client.with_options(timeout=5.0).store.list_inventory()
+client.with_options(timeout=5.0).workspaces.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
+)
```
On timeout, an `APITimeoutError` is thrown.
@@ -267,19 +322,23 @@ if response.my_field is None:
The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,
```py
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
client = Dedalus()
-response = client.store.with_raw_response.list_inventory()
+response = client.workspaces.with_raw_response.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
+)
print(response.headers.get('X-My-Header'))
-store = response.parse() # get the object that `store.list_inventory()` would have returned
-print(store)
+workspace = response.parse() # get the object that `workspaces.create()` would have returned
+print(workspace.workspace_id)
```
-These methods return an [`APIResponse`](https://github.com/stainless-sdks/dedalus-python/tree/main/src/dedalus/_response.py) object.
+These methods return an [`APIResponse`](https://github.com/dedalus-labs/dedalus-python/tree/main/src/dedalus_sdk/_response.py) object.
-The async client returns an [`AsyncAPIResponse`](https://github.com/stainless-sdks/dedalus-python/tree/main/src/dedalus/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.
+The async client returns an [`AsyncAPIResponse`](https://github.com/dedalus-labs/dedalus-python/tree/main/src/dedalus_sdk/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.
#### `.with_streaming_response`
@@ -288,7 +347,11 @@ The above interface eagerly reads the full response body when you make the reque
To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.
```python
-with client.store.with_streaming_response.list_inventory() as response:
+with client.workspaces.with_streaming_response.create(
+ memory_mib=2048,
+ storage_gib=10,
+ vcpu=1,
+) as response:
print(response.headers.get("X-My-Header"))
for line in response.iter_lines():
@@ -341,7 +404,7 @@ You can directly override the [httpx client](https://www.python-httpx.org/api/#c
```python
import httpx
-from dedalus import Dedalus, DefaultHttpxClient
+from dedalus_sdk import Dedalus, DefaultHttpxClient
client = Dedalus(
# Or use the `DEDALUS_BASE_URL` env var
@@ -364,7 +427,7 @@ client.with_options(http_client=DefaultHttpxClient(...))
By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.
```py
-from dedalus import Dedalus
+from dedalus_sdk import Dedalus
with Dedalus() as client:
# make requests here
@@ -383,7 +446,7 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
-We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/dedalus-python/issues) with questions, bugs, or suggestions.
+We are keen for your feedback; please open an [issue](https://www.github.com/dedalus-labs/dedalus-python/issues) with questions, bugs, or suggestions.
### Determining the installed version
@@ -392,8 +455,8 @@ If you've upgraded to the latest version but aren't seeing any new features you
You can determine the version that is being used at runtime with:
```py
-import dedalus
-print(dedalus.__version__)
+import dedalus_sdk
+print(dedalus_sdk.__version__)
```
## Requirements
diff --git a/SECURITY.md b/SECURITY.md
index e53b133..8efb336 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -18,6 +18,10 @@ before making any information public.
If you encounter security issues that are not directly related to SDKs but pertain to the services
or products provided by Dedalus, please follow the respective company's security reporting guidelines.
+### Dedalus Terms and Policies
+
+Please contact security@dedaluslabs.ai for any questions or concerns regarding the security of our services.
+
---
Thank you for helping us keep the SDKs and systems they interact with secure.
diff --git a/api.md b/api.md
index b90f998..d38e6c0 100644
--- a/api.md
+++ b/api.md
@@ -1,68 +1,116 @@
-# Shared Types
+# Workspaces
+
+Types:
```python
-from dedalus.types import Order
+from dedalus_sdk.types import CreateParams, LifecycleStatus, UpdateParams, Workspace, WorkspaceList
```
-# Pets
+Methods:
+
+- client.workspaces.create(\*\*params) -> Workspace
+- client.workspaces.retrieve(workspace_id) -> Workspace
+- client.workspaces.update(workspace_id, \*\*params) -> Workspace
+- client.workspaces.list(\*\*params) -> SyncWorkspaceList[Item]
+- client.workspaces.delete(workspace_id) -> Workspace
+
+## Artifacts
Types:
```python
-from dedalus.types import (
- Category,
- Pet,
- PetFindByStatusResponse,
- PetFindByTagsResponse,
- PetUploadImageResponse,
-)
+from dedalus_sdk.types.workspaces import Artifact, ArtifactList
```
Methods:
-- client.pets.create(\*\*params) -> Pet
-- client.pets.retrieve(pet_id) -> Pet
-- client.pets.update(\*\*params) -> Pet
-- client.pets.delete(pet_id) -> None
-- client.pets.find_by_status(\*\*params) -> PetFindByStatusResponse
-- client.pets.find_by_tags(\*\*params) -> PetFindByTagsResponse
-- client.pets.update_by_id(pet_id, \*\*params) -> None
-- client.pets.upload_image(pet_id, image, \*\*params) -> PetUploadImageResponse
+- client.workspaces.artifacts.retrieve(artifact_id, \*, workspace_id) -> Artifact
+- client.workspaces.artifacts.list(workspace_id, \*\*params) -> SyncArtifactList[Artifact]
+- client.workspaces.artifacts.delete(artifact_id, \*, workspace_id) -> Artifact
-# Store
+## Previews
Types:
```python
-from dedalus.types import StoreListInventoryResponse
+from dedalus_sdk.types.workspaces import Preview, PreviewCreateParams, PreviewList
```
Methods:
-- client.store.list_inventory() -> StoreListInventoryResponse
+- client.workspaces.previews.create(workspace_id, \*\*params) -> Preview
+- client.workspaces.previews.retrieve(preview_id, \*, workspace_id) -> Preview
+- client.workspaces.previews.list(workspace_id, \*\*params) -> SyncPreviewList[Preview]
+- client.workspaces.previews.delete(preview_id, \*, workspace_id) -> Preview
-## Orders
+## SSH
+
+Types:
+
+```python
+from dedalus_sdk.types.workspaces import (
+ SSHConnection,
+ SSHHostTrust,
+ SSHSession,
+ SSHSessionCreateParams,
+ SSHSessionList,
+)
+```
Methods:
-- client.store.orders.create(\*\*params) -> Order
-- client.store.orders.retrieve(order_id) -> Order
-- client.store.orders.delete(order_id) -> None
+- client.workspaces.ssh.create(workspace_id, \*\*params) -> SSHSession
+- client.workspaces.ssh.retrieve(session_id, \*, workspace_id) -> SSHSession
+- client.workspaces.ssh.list(workspace_id, \*\*params) -> SyncSSHSessionList[SSHSession]
+- client.workspaces.ssh.delete(session_id, \*, workspace_id) -> SSHSession
-# Users
+## Executions
Types:
```python
-from dedalus.types import User, UserLoginResponse
+from dedalus_sdk.types.workspaces import (
+ ArtifactRef,
+ Execution,
+ ExecutionCreateParams,
+ ExecutionEvent,
+ ExecutionEvents,
+ ExecutionList,
+ ExecutionOutput,
+)
+```
+
+Methods:
+
+- client.workspaces.executions.create(workspace_id, \*\*params) -> Execution
+- client.workspaces.executions.retrieve(execution_id, \*, workspace_id) -> Execution
+- client.workspaces.executions.list(workspace_id, \*\*params) -> SyncExecutionList[Execution]
+- client.workspaces.executions.delete(execution_id, \*, workspace_id) -> Execution
+- client.workspaces.executions.events(execution_id, \*, workspace_id, \*\*params) -> SyncExecutionEvents[ExecutionEvent]
+- client.workspaces.executions.output(execution_id, \*, workspace_id) -> ExecutionOutput
+
+## Terminals
+
+Types:
+
+```python
+from dedalus_sdk.types.workspaces import (
+ Terminal,
+ TerminalClientEvent,
+ TerminalClosedEvent,
+ TerminalCreateParams,
+ TerminalErrorEvent,
+ TerminalInputEvent,
+ TerminalList,
+ TerminalOutputEvent,
+ TerminalResizeEvent,
+ TerminalServerEvent,
+)
```
Methods:
-- client.users.create(\*\*params) -> User
-- client.users.retrieve(username) -> User
-- client.users.update(existing_username, \*\*params) -> None
-- client.users.delete(username) -> None
-- client.users.create_with_list(\*\*params) -> User
-- client.users.login(\*\*params) -> str
-- client.users.logout() -> None
+- client.workspaces.terminals.create(workspace_id, \*\*params) -> Terminal
+- client.workspaces.terminals.retrieve(terminal_id, \*, workspace_id) -> Terminal
+- client.workspaces.terminals.list(workspace_id, \*\*params) -> SyncTerminalList[Terminal]
+- client.workspaces.terminals.delete(terminal_id, \*, workspace_id) -> Terminal
diff --git a/bin/check-release-environment b/bin/check-release-environment
new file mode 100644
index 0000000..1e951e9
--- /dev/null
+++ b/bin/check-release-environment
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+errors=()
+
+lenErrors=${#errors[@]}
+
+if [[ lenErrors -gt 0 ]]; then
+ echo -e "Found the following errors in the release environment:\n"
+
+ for error in "${errors[@]}"; do
+ echo -e "- $error\n"
+ done
+
+ exit 1
+fi
+
+echo "The environment is ready to push releases!"
diff --git a/bin/publish-pypi b/bin/publish-pypi
index e72ca2f..5895700 100644
--- a/bin/publish-pypi
+++ b/bin/publish-pypi
@@ -4,4 +4,8 @@ set -eux
rm -rf dist
mkdir -p dist
uv build
-uv publish --token=$PYPI_TOKEN
+if [ -n "${PYPI_TOKEN:-}" ]; then
+ uv publish --token=$PYPI_TOKEN
+else
+ uv publish
+fi
diff --git a/pyproject.toml b/pyproject.toml
index a7e6544..e9451f8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,17 +1,17 @@
[project]
-name = "dedalus"
+name = "dedalus-sdk"
version = "0.0.1"
-description = "The official Python library for the dedalus API"
+description = "The official Python library for the Dedalus API"
dynamic = ["readme"]
-license = "Apache-2.0"
+license = "MIT"
authors = [
-{ name = "Dedalus", email = "" },
+{ name = "Dedalus", email = "oss@dedaluslabs.ai" },
]
dependencies = [
"httpx>=0.23.0, <1",
"pydantic>=1.9.0, <3",
- "typing-extensions>=4.10, <5",
+ "typing-extensions>=4.14, <5",
"anyio>=3.5.0, <5",
"distro>=1.7.0, <2",
"sniffio",
@@ -33,15 +33,16 @@ classifiers = [
"Operating System :: POSIX :: Linux",
"Operating System :: Microsoft :: Windows",
"Topic :: Software Development :: Libraries :: Python Modules",
- "License :: OSI Approved :: Apache Software License"
+ "License :: OSI Approved :: MIT License"
]
[project.urls]
-Homepage = "https://github.com/stainless-sdks/dedalus-python"
-Repository = "https://github.com/stainless-sdks/dedalus-python"
+Homepage = "https://github.com/dedalus-labs/dedalus-python"
+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
@@ -86,7 +87,7 @@ include = [
]
[tool.hatch.build.targets.wheel]
-packages = ["src/dedalus"]
+packages = ["src/dedalus_sdk"]
[tool.hatch.build.targets.sdist]
# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc)
@@ -112,7 +113,7 @@ path = "README.md"
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
# replace relative links with absolute links
pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)'
-replacement = '[\1](https://github.com/stainless-sdks/dedalus-python/tree/main/\g<2>)'
+replacement = '[\1](https://github.com/dedalus-labs/dedalus-python/tree/main/\g<2>)'
[tool.pytest.ini_options]
testpaths = ["tests"]
@@ -154,7 +155,7 @@ show_error_codes = true
#
# We also exclude our `tests` as mypy doesn't always infer
# types correctly and Pyright will still catch any type errors.
-exclude = ['src/dedalus/_files.py', '_dev/.*.py', 'tests/.*']
+exclude = ['src/dedalus_sdk/_files.py', '_dev/.*.py', 'tests/.*']
strict_equality = true
implicit_reexport = true
@@ -246,7 +247,7 @@ length-sort = true
length-sort-straight = true
combine-as-imports = true
extra-standard-library = ["typing_extensions"]
-known-first-party = ["dedalus", "tests"]
+known-first-party = ["dedalus_sdk", "tests"]
[tool.ruff.lint.per-file-ignores]
"bin/**.py" = ["T201", "T203"]
diff --git a/release-please-config.json b/release-please-config.json
new file mode 100644
index 0000000..65fbc85
--- /dev/null
+++ b/release-please-config.json
@@ -0,0 +1,69 @@
+{
+ "packages": {
+ ".": {}
+ },
+ "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json",
+ "include-v-in-tag": true,
+ "include-component-in-tag": false,
+ "versioning": "prerelease",
+ "prerelease": true,
+ "bump-minor-pre-major": true,
+ "bump-patch-for-minor-pre-major": false,
+ "pull-request-header": "Automated Release PR",
+ "pull-request-title-pattern": "release: ${version}",
+ "changelog-sections": [
+ {
+ "type": "feat",
+ "section": "Features"
+ },
+ {
+ "type": "fix",
+ "section": "Bug Fixes"
+ },
+ {
+ "type": "perf",
+ "section": "Performance Improvements"
+ },
+ {
+ "type": "revert",
+ "section": "Reverts"
+ },
+ {
+ "type": "chore",
+ "section": "Chores"
+ },
+ {
+ "type": "docs",
+ "section": "Documentation"
+ },
+ {
+ "type": "style",
+ "section": "Styles"
+ },
+ {
+ "type": "refactor",
+ "section": "Refactors"
+ },
+ {
+ "type": "test",
+ "section": "Tests",
+ "hidden": true
+ },
+ {
+ "type": "build",
+ "section": "Build System"
+ },
+ {
+ "type": "ci",
+ "section": "Continuous Integration",
+ "hidden": true
+ }
+ ],
+ "reviewers": [
+ "@windsornguyen"
+ ],
+ "release-type": "python",
+ "extra-files": [
+ "src/dedalus_sdk/_version.py"
+ ]
+}
\ No newline at end of file
diff --git a/requirements-dev.lock b/requirements-dev.lock
index e8141e6..7207341 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -5,7 +5,7 @@ annotated-types==0.7.0
# via pydantic
anyio==4.12.1
# via
- # dedalus
+ # dedalus-sdk
# httpx
backports-asyncio-runner==1.2.0 ; python_full_version < '3.11'
# via pytest-asyncio
@@ -17,7 +17,7 @@ colorama==0.4.6 ; sys_platform == 'win32'
# via pytest
dirty-equals==0.11
distro==1.9.0
- # via dedalus
+ # via dedalus-sdk
exceptiongroup==1.3.1 ; python_full_version < '3.11'
# via
# anyio
@@ -30,7 +30,7 @@ httpcore==1.0.9
# via httpx
httpx==0.28.1
# via
- # dedalus
+ # dedalus-sdk
# respx
idna==3.11
# via
@@ -59,7 +59,7 @@ pathspec==1.0.3
pluggy==1.6.0
# via pytest
pydantic==2.12.5
- # via dedalus
+ # via dedalus-sdk
pydantic-core==2.41.5
# via pydantic
pygments==2.19.2
@@ -86,7 +86,7 @@ ruff==0.14.13
six==1.17.0 ; python_full_version < '3.10'
# via python-dateutil
sniffio==1.3.1
- # via dedalus
+ # via dedalus-sdk
time-machine==2.19.0 ; python_full_version < '3.10'
time-machine==3.2.0 ; python_full_version >= '3.10'
tomli==2.4.0 ; python_full_version < '3.11'
@@ -96,7 +96,7 @@ tomli==2.4.0 ; python_full_version < '3.11'
typing-extensions==4.15.0
# via
# anyio
- # dedalus
+ # dedalus-sdk
# exceptiongroup
# mypy
# pydantic
diff --git a/scripts/lint b/scripts/lint
index 5c92122..5887ad5 100755
--- a/scripts/lint
+++ b/scripts/lint
@@ -19,4 +19,4 @@ echo "==> Running mypy"
uv run mypy .
echo "==> Making sure it imports"
-uv run python -c 'import dedalus'
+uv run python -c 'import dedalus_sdk'
diff --git a/scripts/mock b/scripts/mock
new file mode 100755
index 0000000..bcf3b39
--- /dev/null
+++ b/scripts/mock
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "$0")/.."
+
+if [[ -n "$1" && "$1" != '--'* ]]; then
+ URL="$1"
+ shift
+else
+ URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)"
+fi
+
+# Check if the URL is empty
+if [ -z "$URL" ]; then
+ echo "Error: No OpenAPI spec path/url provided or found in .stats.yml"
+ exit 1
+fi
+
+echo "==> Starting mock server with URL ${URL}"
+
+# Run prism mock on the given spec
+if [ "$1" == "--daemon" ]; then
+ # Pre-install the package so the download doesn't eat into the startup timeout
+ npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version
+
+ npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log &
+
+ # Wait for server to come online (max 30s)
+ echo -n "Waiting for server"
+ attempts=0
+ while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
+ attempts=$((attempts + 1))
+ if [ "$attempts" -ge 300 ]; then
+ echo
+ echo "Timed out waiting for Prism server to start"
+ cat .prism.log
+ exit 1
+ fi
+ echo -n "."
+ sleep 0.1
+ done
+
+ if grep -q "✖ fatal" ".prism.log"; then
+ cat .prism.log
+ exit 1
+ fi
+
+ echo
+else
+ npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL"
+fi
diff --git a/scripts/test b/scripts/test
index fe50ebb..b56970b 100755
--- a/scripts/test
+++ b/scripts/test
@@ -4,7 +4,53 @@ set -e
cd "$(dirname "$0")/.."
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+NC='\033[0m' # No Color
+function prism_is_running() {
+ curl --silent "http://localhost:4010" >/dev/null 2>&1
+}
+
+kill_server_on_port() {
+ pids=$(lsof -t -i tcp:"$1" || echo "")
+ if [ "$pids" != "" ]; then
+ kill "$pids"
+ echo "Stopped $pids."
+ fi
+}
+
+function is_overriding_api_base_url() {
+ [ -n "$TEST_API_BASE_URL" ]
+}
+
+if ! is_overriding_api_base_url && ! prism_is_running ; then
+ # When we exit this script, make sure to kill the background mock server process
+ trap 'kill_server_on_port 4010' EXIT
+
+ # Start the dev server
+ ./scripts/mock --daemon
+fi
+
+if is_overriding_api_base_url ; then
+ echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}"
+ echo
+elif ! prism_is_running ; then
+ echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server"
+ echo -e "running against your OpenAPI spec."
+ echo
+ echo -e "To run the server, pass in the path or url of your OpenAPI"
+ echo -e "spec to the prism command:"
+ echo
+ echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}"
+ echo
+
+ exit 1
+else
+ echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}"
+ echo
+fi
export DEFER_PYDANTIC_BUILD=false
diff --git a/src/dedalus/resources/__init__.py b/src/dedalus/resources/__init__.py
deleted file mode 100644
index d288c6d..0000000
--- a/src/dedalus/resources/__init__.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .pets import (
- PetsResource,
- AsyncPetsResource,
- PetsResourceWithRawResponse,
- AsyncPetsResourceWithRawResponse,
- PetsResourceWithStreamingResponse,
- AsyncPetsResourceWithStreamingResponse,
-)
-from .store import (
- StoreResource,
- AsyncStoreResource,
- StoreResourceWithRawResponse,
- AsyncStoreResourceWithRawResponse,
- StoreResourceWithStreamingResponse,
- AsyncStoreResourceWithStreamingResponse,
-)
-from .users import (
- UsersResource,
- AsyncUsersResource,
- UsersResourceWithRawResponse,
- AsyncUsersResourceWithRawResponse,
- UsersResourceWithStreamingResponse,
- AsyncUsersResourceWithStreamingResponse,
-)
-
-__all__ = [
- "PetsResource",
- "AsyncPetsResource",
- "PetsResourceWithRawResponse",
- "AsyncPetsResourceWithRawResponse",
- "PetsResourceWithStreamingResponse",
- "AsyncPetsResourceWithStreamingResponse",
- "StoreResource",
- "AsyncStoreResource",
- "StoreResourceWithRawResponse",
- "AsyncStoreResourceWithRawResponse",
- "StoreResourceWithStreamingResponse",
- "AsyncStoreResourceWithStreamingResponse",
- "UsersResource",
- "AsyncUsersResource",
- "UsersResourceWithRawResponse",
- "AsyncUsersResourceWithRawResponse",
- "UsersResourceWithStreamingResponse",
- "AsyncUsersResourceWithStreamingResponse",
-]
diff --git a/src/dedalus/resources/pets.py b/src/dedalus/resources/pets.py
deleted file mode 100644
index 583b7f4..0000000
--- a/src/dedalus/resources/pets.py
+++ /dev/null
@@ -1,872 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import os
-from typing import Iterable
-from typing_extensions import Literal
-
-import httpx
-
-from ..types import (
- pet_create_params,
- pet_update_params,
- pet_find_by_tags_params,
- pet_update_by_id_params,
- pet_upload_image_params,
- pet_find_by_status_params,
-)
-from .._files import read_file_content, async_read_file_content
-from .._types import (
- Body,
- Omit,
- Query,
- Headers,
- NoneType,
- NotGiven,
- BinaryTypes,
- FileContent,
- SequenceNotStr,
- AsyncBinaryTypes,
- 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 ..types.pet import Pet
-from .._base_client import make_request_options
-from ..types.category_param import CategoryParam
-from ..types.pet_find_by_tags_response import PetFindByTagsResponse
-from ..types.pet_upload_image_response import PetUploadImageResponse
-from ..types.pet_find_by_status_response import PetFindByStatusResponse
-
-__all__ = ["PetsResource", "AsyncPetsResource"]
-
-
-class PetsResource(SyncAPIResource):
- """Everything about your Pets"""
-
- @cached_property
- def with_raw_response(self) -> PetsResourceWithRawResponse:
- """
- 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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
- """
- return PetsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> PetsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
- """
- return PetsResourceWithStreamingResponse(self)
-
- def create(
- self,
- *,
- name: str,
- photo_urls: SequenceNotStr[str],
- id: int | Omit = omit,
- category: CategoryParam | Omit = omit,
- status: Literal["available", "pending", "sold"] | Omit = omit,
- tags: Iterable[pet_create_params.Tag] | 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,
- ) -> Pet:
- """
- Add a new pet to the store
-
- Args:
- status: pet status in the store
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._post(
- "/pet",
- body=maybe_transform(
- {
- "name": name,
- "photo_urls": photo_urls,
- "id": id,
- "category": category,
- "status": status,
- "tags": tags,
- },
- pet_create_params.PetCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- def retrieve(
- self,
- pet_id: int,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Pet:
- """
- Returns a single pet
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return self._get(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- def update(
- self,
- *,
- name: str,
- photo_urls: SequenceNotStr[str],
- id: int | Omit = omit,
- category: CategoryParam | Omit = omit,
- status: Literal["available", "pending", "sold"] | Omit = omit,
- tags: Iterable[pet_update_params.Tag] | 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,
- ) -> Pet:
- """
- Update an existing pet by Id
-
- Args:
- status: pet status in the store
-
- 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._put(
- "/pet",
- body=maybe_transform(
- {
- "name": name,
- "photo_urls": photo_urls,
- "id": id,
- "category": category,
- "status": status,
- "tags": tags,
- },
- pet_update_params.PetUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- def delete(
- self,
- pet_id: int,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """
- delete a pet
-
- 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
- """
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._delete(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def find_by_status(
- self,
- *,
- status: Literal["available", "pending", "sold"] | 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,
- ) -> PetFindByStatusResponse:
- """
- Multiple status values can be provided with comma separated strings
-
- Args:
- status: Status values that need to be considered for filter
-
- 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(
- "/pet/findByStatus",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform({"status": status}, pet_find_by_status_params.PetFindByStatusParams),
- ),
- cast_to=PetFindByStatusResponse,
- )
-
- def find_by_tags(
- self,
- *,
- tags: SequenceNotStr[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> PetFindByTagsResponse:
- """Multiple tags can be provided with comma separated strings.
-
- Use tag1, tag2, tag3
- for testing.
-
- Args:
- tags: Tags to filter by
-
- 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(
- "/pet/findByTags",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform({"tags": tags}, pet_find_by_tags_params.PetFindByTagsParams),
- ),
- cast_to=PetFindByTagsResponse,
- )
-
- def update_by_id(
- self,
- pet_id: int,
- *,
- name: str | Omit = omit,
- status: 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,
- ) -> None:
- """
- Updates a pet in the store with form data
-
- Args:
- name: Name of pet that needs to be updated
-
- status: Status of pet that needs to be updated
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._post(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "name": name,
- "status": status,
- },
- pet_update_by_id_params.PetUpdateByIDParams,
- ),
- ),
- cast_to=NoneType,
- )
-
- def upload_image(
- self,
- pet_id: int,
- image: FileContent | BinaryTypes,
- *,
- additional_metadata: 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,
- ) -> PetUploadImageResponse:
- """
- uploads an image
-
- Args:
- additional_metadata: Additional Metadata
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- extra_headers = {"Content-Type": "application/octet-stream", **(extra_headers or {})}
- return self._post(
- f"/pet/{pet_id}/uploadImage",
- content=read_file_content(image) if isinstance(image, os.PathLike) else image,
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {"additional_metadata": additional_metadata}, pet_upload_image_params.PetUploadImageParams
- ),
- ),
- cast_to=PetUploadImageResponse,
- )
-
-
-class AsyncPetsResource(AsyncAPIResource):
- """Everything about your Pets"""
-
- @cached_property
- def with_raw_response(self) -> AsyncPetsResourceWithRawResponse:
- """
- 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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
- """
- return AsyncPetsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncPetsResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
- """
- return AsyncPetsResourceWithStreamingResponse(self)
-
- async def create(
- self,
- *,
- name: str,
- photo_urls: SequenceNotStr[str],
- id: int | Omit = omit,
- category: CategoryParam | Omit = omit,
- status: Literal["available", "pending", "sold"] | Omit = omit,
- tags: Iterable[pet_create_params.Tag] | 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,
- ) -> Pet:
- """
- Add a new pet to the store
-
- Args:
- status: pet status in the store
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._post(
- "/pet",
- body=await async_maybe_transform(
- {
- "name": name,
- "photo_urls": photo_urls,
- "id": id,
- "category": category,
- "status": status,
- "tags": tags,
- },
- pet_create_params.PetCreateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- async def retrieve(
- self,
- pet_id: int,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Pet:
- """
- Returns a single pet
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- return await self._get(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- async def update(
- self,
- *,
- name: str,
- photo_urls: SequenceNotStr[str],
- id: int | Omit = omit,
- category: CategoryParam | Omit = omit,
- status: Literal["available", "pending", "sold"] | Omit = omit,
- tags: Iterable[pet_update_params.Tag] | 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,
- ) -> Pet:
- """
- Update an existing pet by Id
-
- Args:
- status: pet status in the store
-
- 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._put(
- "/pet",
- body=await async_maybe_transform(
- {
- "name": name,
- "photo_urls": photo_urls,
- "id": id,
- "category": category,
- "status": status,
- "tags": tags,
- },
- pet_update_params.PetUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Pet,
- )
-
- async def delete(
- self,
- pet_id: int,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """
- delete a pet
-
- 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
- """
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._delete(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def find_by_status(
- self,
- *,
- status: Literal["available", "pending", "sold"] | 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,
- ) -> PetFindByStatusResponse:
- """
- Multiple status values can be provided with comma separated strings
-
- Args:
- status: Status values that need to be considered for filter
-
- 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(
- "/pet/findByStatus",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform({"status": status}, pet_find_by_status_params.PetFindByStatusParams),
- ),
- cast_to=PetFindByStatusResponse,
- )
-
- async def find_by_tags(
- self,
- *,
- tags: SequenceNotStr[str] | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> PetFindByTagsResponse:
- """Multiple tags can be provided with comma separated strings.
-
- Use tag1, tag2, tag3
- for testing.
-
- Args:
- tags: Tags to filter by
-
- 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(
- "/pet/findByTags",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform({"tags": tags}, pet_find_by_tags_params.PetFindByTagsParams),
- ),
- cast_to=PetFindByTagsResponse,
- )
-
- async def update_by_id(
- self,
- pet_id: int,
- *,
- name: str | Omit = omit,
- status: 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,
- ) -> None:
- """
- Updates a pet in the store with form data
-
- Args:
- name: Name of pet that needs to be updated
-
- status: Status of pet that needs to be updated
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._post(
- f"/pet/{pet_id}",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "name": name,
- "status": status,
- },
- pet_update_by_id_params.PetUpdateByIDParams,
- ),
- ),
- cast_to=NoneType,
- )
-
- async def upload_image(
- self,
- pet_id: int,
- image: FileContent | AsyncBinaryTypes,
- *,
- additional_metadata: 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,
- ) -> PetUploadImageResponse:
- """
- uploads an image
-
- Args:
- additional_metadata: Additional Metadata
-
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- extra_headers = {"Content-Type": "application/octet-stream", **(extra_headers or {})}
- return await self._post(
- f"/pet/{pet_id}/uploadImage",
- content=await async_read_file_content(image) if isinstance(image, os.PathLike) else image,
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"additional_metadata": additional_metadata}, pet_upload_image_params.PetUploadImageParams
- ),
- ),
- cast_to=PetUploadImageResponse,
- )
-
-
-class PetsResourceWithRawResponse:
- def __init__(self, pets: PetsResource) -> None:
- self._pets = pets
-
- self.create = to_raw_response_wrapper(
- pets.create,
- )
- self.retrieve = to_raw_response_wrapper(
- pets.retrieve,
- )
- self.update = to_raw_response_wrapper(
- pets.update,
- )
- self.delete = to_raw_response_wrapper(
- pets.delete,
- )
- self.find_by_status = to_raw_response_wrapper(
- pets.find_by_status,
- )
- self.find_by_tags = to_raw_response_wrapper(
- pets.find_by_tags,
- )
- self.update_by_id = to_raw_response_wrapper(
- pets.update_by_id,
- )
- self.upload_image = to_raw_response_wrapper(
- pets.upload_image,
- )
-
-
-class AsyncPetsResourceWithRawResponse:
- def __init__(self, pets: AsyncPetsResource) -> None:
- self._pets = pets
-
- self.create = async_to_raw_response_wrapper(
- pets.create,
- )
- self.retrieve = async_to_raw_response_wrapper(
- pets.retrieve,
- )
- self.update = async_to_raw_response_wrapper(
- pets.update,
- )
- self.delete = async_to_raw_response_wrapper(
- pets.delete,
- )
- self.find_by_status = async_to_raw_response_wrapper(
- pets.find_by_status,
- )
- self.find_by_tags = async_to_raw_response_wrapper(
- pets.find_by_tags,
- )
- self.update_by_id = async_to_raw_response_wrapper(
- pets.update_by_id,
- )
- self.upload_image = async_to_raw_response_wrapper(
- pets.upload_image,
- )
-
-
-class PetsResourceWithStreamingResponse:
- def __init__(self, pets: PetsResource) -> None:
- self._pets = pets
-
- self.create = to_streamed_response_wrapper(
- pets.create,
- )
- self.retrieve = to_streamed_response_wrapper(
- pets.retrieve,
- )
- self.update = to_streamed_response_wrapper(
- pets.update,
- )
- self.delete = to_streamed_response_wrapper(
- pets.delete,
- )
- self.find_by_status = to_streamed_response_wrapper(
- pets.find_by_status,
- )
- self.find_by_tags = to_streamed_response_wrapper(
- pets.find_by_tags,
- )
- self.update_by_id = to_streamed_response_wrapper(
- pets.update_by_id,
- )
- self.upload_image = to_streamed_response_wrapper(
- pets.upload_image,
- )
-
-
-class AsyncPetsResourceWithStreamingResponse:
- def __init__(self, pets: AsyncPetsResource) -> None:
- self._pets = pets
-
- self.create = async_to_streamed_response_wrapper(
- pets.create,
- )
- self.retrieve = async_to_streamed_response_wrapper(
- pets.retrieve,
- )
- self.update = async_to_streamed_response_wrapper(
- pets.update,
- )
- self.delete = async_to_streamed_response_wrapper(
- pets.delete,
- )
- self.find_by_status = async_to_streamed_response_wrapper(
- pets.find_by_status,
- )
- self.find_by_tags = async_to_streamed_response_wrapper(
- pets.find_by_tags,
- )
- self.update_by_id = async_to_streamed_response_wrapper(
- pets.update_by_id,
- )
- self.upload_image = async_to_streamed_response_wrapper(
- pets.upload_image,
- )
diff --git a/src/dedalus/resources/store/__init__.py b/src/dedalus/resources/store/__init__.py
deleted file mode 100644
index 24ecda0..0000000
--- a/src/dedalus/resources/store/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .store import (
- StoreResource,
- AsyncStoreResource,
- StoreResourceWithRawResponse,
- AsyncStoreResourceWithRawResponse,
- StoreResourceWithStreamingResponse,
- AsyncStoreResourceWithStreamingResponse,
-)
-from .orders import (
- OrdersResource,
- AsyncOrdersResource,
- OrdersResourceWithRawResponse,
- AsyncOrdersResourceWithRawResponse,
- OrdersResourceWithStreamingResponse,
- AsyncOrdersResourceWithStreamingResponse,
-)
-
-__all__ = [
- "OrdersResource",
- "AsyncOrdersResource",
- "OrdersResourceWithRawResponse",
- "AsyncOrdersResourceWithRawResponse",
- "OrdersResourceWithStreamingResponse",
- "AsyncOrdersResourceWithStreamingResponse",
- "StoreResource",
- "AsyncStoreResource",
- "StoreResourceWithRawResponse",
- "AsyncStoreResourceWithRawResponse",
- "StoreResourceWithStreamingResponse",
- "AsyncStoreResourceWithStreamingResponse",
-]
diff --git a/src/dedalus/resources/store/store.py b/src/dedalus/resources/store/store.py
deleted file mode 100644
index 1d0940c..0000000
--- a/src/dedalus/resources/store/store.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from .orders import (
- OrdersResource,
- AsyncOrdersResource,
- OrdersResourceWithRawResponse,
- AsyncOrdersResourceWithRawResponse,
- OrdersResourceWithStreamingResponse,
- AsyncOrdersResourceWithStreamingResponse,
-)
-from ..._types import Body, Query, Headers, NotGiven, not_given
-from ..._compat import cached_property
-from ..._resource import SyncAPIResource, AsyncAPIResource
-from ..._response import (
- to_raw_response_wrapper,
- to_streamed_response_wrapper,
- async_to_raw_response_wrapper,
- async_to_streamed_response_wrapper,
-)
-from ..._base_client import make_request_options
-from ...types.store_list_inventory_response import StoreListInventoryResponse
-
-__all__ = ["StoreResource", "AsyncStoreResource"]
-
-
-class StoreResource(SyncAPIResource):
- """Access to Petstore orders"""
-
- @cached_property
- def orders(self) -> OrdersResource:
- """Access to Petstore orders"""
- return OrdersResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> StoreResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
- """
- return StoreResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> StoreResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
- """
- return StoreResourceWithStreamingResponse(self)
-
- def list_inventory(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> StoreListInventoryResponse:
- """Returns a map of status codes to quantities"""
- return self._get(
- "/store/inventory",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=StoreListInventoryResponse,
- )
-
-
-class AsyncStoreResource(AsyncAPIResource):
- """Access to Petstore orders"""
-
- @cached_property
- def orders(self) -> AsyncOrdersResource:
- """Access to Petstore orders"""
- return AsyncOrdersResource(self._client)
-
- @cached_property
- def with_raw_response(self) -> AsyncStoreResourceWithRawResponse:
- """
- This property can be used as a prefix for any HTTP method call to return
- the raw response object instead of the parsed content.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
- """
- return AsyncStoreResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncStoreResourceWithStreamingResponse:
- """
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
-
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
- """
- return AsyncStoreResourceWithStreamingResponse(self)
-
- async def list_inventory(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> StoreListInventoryResponse:
- """Returns a map of status codes to quantities"""
- return await self._get(
- "/store/inventory",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=StoreListInventoryResponse,
- )
-
-
-class StoreResourceWithRawResponse:
- def __init__(self, store: StoreResource) -> None:
- self._store = store
-
- self.list_inventory = to_raw_response_wrapper(
- store.list_inventory,
- )
-
- @cached_property
- def orders(self) -> OrdersResourceWithRawResponse:
- """Access to Petstore orders"""
- return OrdersResourceWithRawResponse(self._store.orders)
-
-
-class AsyncStoreResourceWithRawResponse:
- def __init__(self, store: AsyncStoreResource) -> None:
- self._store = store
-
- self.list_inventory = async_to_raw_response_wrapper(
- store.list_inventory,
- )
-
- @cached_property
- def orders(self) -> AsyncOrdersResourceWithRawResponse:
- """Access to Petstore orders"""
- return AsyncOrdersResourceWithRawResponse(self._store.orders)
-
-
-class StoreResourceWithStreamingResponse:
- def __init__(self, store: StoreResource) -> None:
- self._store = store
-
- self.list_inventory = to_streamed_response_wrapper(
- store.list_inventory,
- )
-
- @cached_property
- def orders(self) -> OrdersResourceWithStreamingResponse:
- """Access to Petstore orders"""
- return OrdersResourceWithStreamingResponse(self._store.orders)
-
-
-class AsyncStoreResourceWithStreamingResponse:
- def __init__(self, store: AsyncStoreResource) -> None:
- self._store = store
-
- self.list_inventory = async_to_streamed_response_wrapper(
- store.list_inventory,
- )
-
- @cached_property
- def orders(self) -> AsyncOrdersResourceWithStreamingResponse:
- """Access to Petstore orders"""
- return AsyncOrdersResourceWithStreamingResponse(self._store.orders)
diff --git a/src/dedalus/types/__init__.py b/src/dedalus/types/__init__.py
deleted file mode 100644
index 6b7a839..0000000
--- a/src/dedalus/types/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from .pet import Pet as Pet
-from .user import User as User
-from .shared import Order as Order
-from .category import Category as Category
-from .user_param import UserParam as UserParam
-from .category_param import CategoryParam as CategoryParam
-from .pet_create_params import PetCreateParams as PetCreateParams
-from .pet_update_params import PetUpdateParams as PetUpdateParams
-from .user_login_params import UserLoginParams as UserLoginParams
-from .user_create_params import UserCreateParams as UserCreateParams
-from .user_update_params import UserUpdateParams as UserUpdateParams
-from .user_login_response import UserLoginResponse as UserLoginResponse
-from .pet_find_by_tags_params import PetFindByTagsParams as PetFindByTagsParams
-from .pet_update_by_id_params import PetUpdateByIDParams as PetUpdateByIDParams
-from .pet_upload_image_params import PetUploadImageParams as PetUploadImageParams
-from .pet_find_by_status_params import PetFindByStatusParams as PetFindByStatusParams
-from .pet_find_by_tags_response import PetFindByTagsResponse as PetFindByTagsResponse
-from .pet_upload_image_response import PetUploadImageResponse as PetUploadImageResponse
-from .pet_find_by_status_response import PetFindByStatusResponse as PetFindByStatusResponse
-from .user_create_with_list_params import UserCreateWithListParams as UserCreateWithListParams
-from .store_list_inventory_response import StoreListInventoryResponse as StoreListInventoryResponse
diff --git a/src/dedalus/types/category.py b/src/dedalus/types/category.py
deleted file mode 100644
index 2ee2999..0000000
--- a/src/dedalus/types/category.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-
-from .._models import BaseModel
-
-__all__ = ["Category"]
-
-
-class Category(BaseModel):
- id: Optional[int] = None
-
- name: Optional[str] = None
diff --git a/src/dedalus/types/pet.py b/src/dedalus/types/pet.py
deleted file mode 100644
index b9aebf6..0000000
--- a/src/dedalus/types/pet.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List, Optional
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-from .category import Category
-
-__all__ = ["Pet", "Tag"]
-
-
-class Tag(BaseModel):
- id: Optional[int] = None
-
- name: Optional[str] = None
-
-
-class Pet(BaseModel):
- name: str
-
- photo_urls: List[str] = FieldInfo(alias="photoUrls")
-
- id: Optional[int] = None
-
- category: Optional[Category] = None
-
- status: Optional[Literal["available", "pending", "sold"]] = None
- """pet status in the store"""
-
- tags: Optional[List[Tag]] = None
diff --git a/src/dedalus/types/pet_create_params.py b/src/dedalus/types/pet_create_params.py
deleted file mode 100644
index 987a634..0000000
--- a/src/dedalus/types/pet_create_params.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Iterable
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-from .category_param import CategoryParam
-
-__all__ = ["PetCreateParams", "Tag"]
-
-
-class PetCreateParams(TypedDict, total=False):
- name: Required[str]
-
- photo_urls: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="photoUrls")]]
-
- id: int
-
- category: CategoryParam
-
- status: Literal["available", "pending", "sold"]
- """pet status in the store"""
-
- tags: Iterable[Tag]
-
-
-class Tag(TypedDict, total=False):
- id: int
-
- name: str
diff --git a/src/dedalus/types/pet_find_by_status_params.py b/src/dedalus/types/pet_find_by_status_params.py
deleted file mode 100644
index a9e4cc8..0000000
--- a/src/dedalus/types/pet_find_by_status_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 Literal, TypedDict
-
-__all__ = ["PetFindByStatusParams"]
-
-
-class PetFindByStatusParams(TypedDict, total=False):
- status: Literal["available", "pending", "sold"]
- """Status values that need to be considered for filter"""
diff --git a/src/dedalus/types/pet_find_by_status_response.py b/src/dedalus/types/pet_find_by_status_response.py
deleted file mode 100644
index 95eed04..0000000
--- a/src/dedalus/types/pet_find_by_status_response.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-from .pet import Pet
-
-__all__ = ["PetFindByStatusResponse"]
-
-PetFindByStatusResponse: TypeAlias = List[Pet]
diff --git a/src/dedalus/types/pet_find_by_tags_params.py b/src/dedalus/types/pet_find_by_tags_params.py
deleted file mode 100644
index 9755216..0000000
--- a/src/dedalus/types/pet_find_by_tags_params.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import TypedDict
-
-from .._types import SequenceNotStr
-
-__all__ = ["PetFindByTagsParams"]
-
-
-class PetFindByTagsParams(TypedDict, total=False):
- tags: SequenceNotStr[str]
- """Tags to filter by"""
diff --git a/src/dedalus/types/pet_find_by_tags_response.py b/src/dedalus/types/pet_find_by_tags_response.py
deleted file mode 100644
index 32314ba..0000000
--- a/src/dedalus/types/pet_find_by_tags_response.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import List
-from typing_extensions import TypeAlias
-
-from .pet import Pet
-
-__all__ = ["PetFindByTagsResponse"]
-
-PetFindByTagsResponse: TypeAlias = List[Pet]
diff --git a/src/dedalus/types/pet_update_by_id_params.py b/src/dedalus/types/pet_update_by_id_params.py
deleted file mode 100644
index 96b4230..0000000
--- a/src/dedalus/types/pet_update_by_id_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 TypedDict
-
-__all__ = ["PetUpdateByIDParams"]
-
-
-class PetUpdateByIDParams(TypedDict, total=False):
- name: str
- """Name of pet that needs to be updated"""
-
- status: str
- """Status of pet that needs to be updated"""
diff --git a/src/dedalus/types/pet_update_params.py b/src/dedalus/types/pet_update_params.py
deleted file mode 100644
index e718bbf..0000000
--- a/src/dedalus/types/pet_update_params.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Iterable
-from typing_extensions import Literal, Required, Annotated, TypedDict
-
-from .._types import SequenceNotStr
-from .._utils import PropertyInfo
-from .category_param import CategoryParam
-
-__all__ = ["PetUpdateParams", "Tag"]
-
-
-class PetUpdateParams(TypedDict, total=False):
- name: Required[str]
-
- photo_urls: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="photoUrls")]]
-
- id: int
-
- category: CategoryParam
-
- status: Literal["available", "pending", "sold"]
- """pet status in the store"""
-
- tags: Iterable[Tag]
-
-
-class Tag(TypedDict, total=False):
- id: int
-
- name: str
diff --git a/src/dedalus/types/pet_upload_image_params.py b/src/dedalus/types/pet_upload_image_params.py
deleted file mode 100644
index af28186..0000000
--- a/src/dedalus/types/pet_upload_image_params.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["PetUploadImageParams"]
-
-
-class PetUploadImageParams(TypedDict, total=False):
- additional_metadata: Annotated[str, PropertyInfo(alias="additionalMetadata")]
- """Additional Metadata"""
diff --git a/src/dedalus/types/pet_upload_image_response.py b/src/dedalus/types/pet_upload_image_response.py
deleted file mode 100644
index 6b39d71..0000000
--- a/src/dedalus/types/pet_upload_image_response.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-
-from .._models import BaseModel
-
-__all__ = ["PetUploadImageResponse"]
-
-
-class PetUploadImageResponse(BaseModel):
- code: Optional[int] = None
-
- message: Optional[str] = None
-
- type: Optional[str] = None
diff --git a/src/dedalus/types/shared/__init__.py b/src/dedalus/types/shared/__init__.py
deleted file mode 100644
index 3d5c73d..0000000
--- a/src/dedalus/types/shared/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from .order import Order as Order
diff --git a/src/dedalus/types/shared/order.py b/src/dedalus/types/shared/order.py
deleted file mode 100644
index cf3b571..0000000
--- a/src/dedalus/types/shared/order.py
+++ /dev/null
@@ -1,26 +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 pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-
-__all__ = ["Order"]
-
-
-class Order(BaseModel):
- id: Optional[int] = None
-
- complete: Optional[bool] = None
-
- pet_id: Optional[int] = FieldInfo(alias="petId", default=None)
-
- quantity: Optional[int] = None
-
- ship_date: Optional[datetime] = FieldInfo(alias="shipDate", default=None)
-
- status: Optional[Literal["placed", "approved", "delivered"]] = None
- """Order Status"""
diff --git a/src/dedalus/types/store/__init__.py b/src/dedalus/types/store/__init__.py
deleted file mode 100644
index f742531..0000000
--- a/src/dedalus/types/store/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from .order_create_params import OrderCreateParams as OrderCreateParams
diff --git a/src/dedalus/types/store/order_create_params.py b/src/dedalus/types/store/order_create_params.py
deleted file mode 100644
index 2eadb10..0000000
--- a/src/dedalus/types/store/order_create_params.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Union
-from datetime import datetime
-from typing_extensions import Literal, Annotated, TypedDict
-
-from ..._utils import PropertyInfo
-
-__all__ = ["OrderCreateParams"]
-
-
-class OrderCreateParams(TypedDict, total=False):
- id: int
-
- complete: bool
-
- pet_id: Annotated[int, PropertyInfo(alias="petId")]
-
- quantity: int
-
- ship_date: Annotated[Union[str, datetime], PropertyInfo(alias="shipDate", format="iso8601")]
-
- status: Literal["placed", "approved", "delivered"]
- """Order Status"""
diff --git a/src/dedalus/types/store_list_inventory_response.py b/src/dedalus/types/store_list_inventory_response.py
deleted file mode 100644
index 0a25d96..0000000
--- a/src/dedalus/types/store_list_inventory_response.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Dict
-from typing_extensions import TypeAlias
-
-__all__ = ["StoreListInventoryResponse"]
-
-StoreListInventoryResponse: TypeAlias = Dict[str, int]
diff --git a/src/dedalus/types/user.py b/src/dedalus/types/user.py
deleted file mode 100644
index db3d251..0000000
--- a/src/dedalus/types/user.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing import Optional
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["User"]
-
-
-class User(BaseModel):
- id: Optional[int] = None
-
- email: Optional[str] = None
-
- first_name: Optional[str] = FieldInfo(alias="firstName", default=None)
-
- last_name: Optional[str] = FieldInfo(alias="lastName", default=None)
-
- password: Optional[str] = None
-
- phone: Optional[str] = None
-
- username: Optional[str] = None
-
- user_status: Optional[int] = FieldInfo(alias="userStatus", default=None)
- """User Status"""
diff --git a/src/dedalus/types/user_create_params.py b/src/dedalus/types/user_create_params.py
deleted file mode 100644
index cf829df..0000000
--- a/src/dedalus/types/user_create_params.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["UserCreateParams"]
-
-
-class UserCreateParams(TypedDict, total=False):
- id: int
-
- email: str
-
- first_name: Annotated[str, PropertyInfo(alias="firstName")]
-
- last_name: Annotated[str, PropertyInfo(alias="lastName")]
-
- password: str
-
- phone: str
-
- username: str
-
- user_status: Annotated[int, PropertyInfo(alias="userStatus")]
- """User Status"""
diff --git a/src/dedalus/types/user_create_with_list_params.py b/src/dedalus/types/user_create_with_list_params.py
deleted file mode 100644
index 32b51db..0000000
--- a/src/dedalus/types/user_create_with_list_params.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing import Iterable
-from typing_extensions import TypedDict
-
-from .user_param import UserParam
-
-__all__ = ["UserCreateWithListParams"]
-
-
-class UserCreateWithListParams(TypedDict, total=False):
- items: Iterable[UserParam]
diff --git a/src/dedalus/types/user_login_params.py b/src/dedalus/types/user_login_params.py
deleted file mode 100644
index 3128ccd..0000000
--- a/src/dedalus/types/user_login_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 TypedDict
-
-__all__ = ["UserLoginParams"]
-
-
-class UserLoginParams(TypedDict, total=False):
- password: str
- """The password for login in clear text"""
-
- username: str
- """The user name for login"""
diff --git a/src/dedalus/types/user_login_response.py b/src/dedalus/types/user_login_response.py
deleted file mode 100644
index 30deea7..0000000
--- a/src/dedalus/types/user_login_response.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from typing_extensions import TypeAlias
-
-__all__ = ["UserLoginResponse"]
-
-UserLoginResponse: TypeAlias = str
diff --git a/src/dedalus/types/user_param.py b/src/dedalus/types/user_param.py
deleted file mode 100644
index cdf6047..0000000
--- a/src/dedalus/types/user_param.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["UserParam"]
-
-
-class UserParam(TypedDict, total=False):
- id: int
-
- email: str
-
- first_name: Annotated[str, PropertyInfo(alias="firstName")]
-
- last_name: Annotated[str, PropertyInfo(alias="lastName")]
-
- password: str
-
- phone: str
-
- username: str
-
- user_status: Annotated[int, PropertyInfo(alias="userStatus")]
- """User Status"""
diff --git a/src/dedalus/types/user_update_params.py b/src/dedalus/types/user_update_params.py
deleted file mode 100644
index 723b8fc..0000000
--- a/src/dedalus/types/user_update_params.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Annotated, TypedDict
-
-from .._utils import PropertyInfo
-
-__all__ = ["UserUpdateParams"]
-
-
-class UserUpdateParams(TypedDict, total=False):
- id: int
-
- email: str
-
- first_name: Annotated[str, PropertyInfo(alias="firstName")]
-
- last_name: Annotated[str, PropertyInfo(alias="lastName")]
-
- password: str
-
- phone: str
-
- username: str
-
- user_status: Annotated[int, PropertyInfo(alias="userStatus")]
- """User Status"""
diff --git a/src/dedalus/__init__.py b/src/dedalus_sdk/__init__.py
similarity index 95%
rename from src/dedalus/__init__.py
rename to src/dedalus_sdk/__init__.py
index cf2bd86..140521a 100644
--- a/src/dedalus/__init__.py
+++ b/src/dedalus_sdk/__init__.py
@@ -81,12 +81,12 @@
# Update the __module__ attribute for exported symbols so that
# error messages point to this module instead of the module
# it was originally defined in, e.g.
-# dedalus._exceptions.NotFoundError -> dedalus.NotFoundError
+# dedalus_sdk._exceptions.NotFoundError -> dedalus_sdk.NotFoundError
__locals = locals()
for __name in __all__:
if not __name.startswith("__"):
try:
- __locals[__name].__module__ = "dedalus"
+ __locals[__name].__module__ = "dedalus_sdk"
except (TypeError, AttributeError):
# Some of our exported symbols are builtins which we can't set attributes for.
pass
diff --git a/src/dedalus/_base_client.py b/src/dedalus_sdk/_base_client.py
similarity index 98%
rename from src/dedalus/_base_client.py
rename to src/dedalus_sdk/_base_client.py
index 2ac9853..23de458 100644
--- a/src/dedalus/_base_client.py
+++ b/src/dedalus_sdk/_base_client.py
@@ -63,7 +63,7 @@
)
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
from ._compat import PYDANTIC_V1, model_copy, model_dump
-from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
+from ._models import GenericModel, SecurityOptions, FinalRequestOptions, validate_type, construct_type
from ._response import (
APIResponse,
BaseAPIResponse,
@@ -393,7 +393,7 @@ def __init__(
if max_retries is None: # pyright: ignore[reportUnnecessaryComparison]
raise TypeError(
- "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `dedalus.DEFAULT_MAX_RETRIES`"
+ "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `dedalus_sdk.DEFAULT_MAX_RETRIES`"
)
def _enforce_trailing_slash(self, url: URL) -> URL:
@@ -432,9 +432,27 @@ def _make_status_error(
) -> _exceptions.APIStatusError:
raise NotImplementedError()
+ def _auth_headers(
+ self,
+ security: SecurityOptions, # noqa: ARG002
+ ) -> dict[str, str]:
+ return {}
+
+ def _auth_query(
+ self,
+ security: SecurityOptions, # noqa: ARG002
+ ) -> dict[str, str]:
+ return {}
+
+ def _custom_auth(
+ self,
+ security: SecurityOptions, # noqa: ARG002
+ ) -> httpx.Auth | None:
+ return None
+
def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers:
custom_headers = options.headers or {}
- headers_dict = _merge_mappings(self.default_headers, custom_headers)
+ headers_dict = _merge_mappings({**self._auth_headers(options.security), **self.default_headers}, custom_headers)
self._validate_headers(headers_dict, custom_headers)
# headers are case-insensitive while dictionaries are not.
@@ -506,7 +524,7 @@ def _build_request(
raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`")
headers = self._build_headers(options, retries_taken=retries_taken)
- params = _merge_mappings(self.default_query, options.params)
+ params = _merge_mappings({**self._auth_query(options.security), **self.default_query}, options.params)
content_type = headers.get("Content-Type")
files = options.files
@@ -671,7 +689,6 @@ def default_headers(self) -> dict[str, str | Omit]:
"Content-Type": "application/json",
"User-Agent": self.user_agent,
**self.platform_headers(),
- **self.auth_headers,
**self._custom_headers,
}
@@ -990,8 +1007,9 @@ def request(
self._prepare_request(request)
kwargs: HttpxSendArgs = {}
- if self.custom_auth is not None:
- kwargs["auth"] = self.custom_auth
+ custom_auth = self._custom_auth(options.security)
+ if custom_auth is not None:
+ kwargs["auth"] = custom_auth
if options.follow_redirects is not None:
kwargs["follow_redirects"] = options.follow_redirects
@@ -1952,6 +1970,7 @@ def make_request_options(
idempotency_key: str | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
post_parser: PostParser | NotGiven = not_given,
+ security: SecurityOptions | None = None,
) -> RequestOptions:
"""Create a dict of type RequestOptions without keys of NotGiven values."""
options: RequestOptions = {}
@@ -1977,6 +1996,9 @@ def make_request_options(
# internal
options["post_parser"] = post_parser # type: ignore
+ if security is not None:
+ options["security"] = security
+
return options
diff --git a/src/dedalus/_client.py b/src/dedalus_sdk/_client.py
similarity index 65%
rename from src/dedalus/_client.py
rename to src/dedalus_sdk/_client.py
index 4665240..4a2dc71 100644
--- a/src/dedalus/_client.py
+++ b/src/dedalus_sdk/_client.py
@@ -12,6 +12,7 @@
from ._qs import Querystring
from ._types import (
Omit,
+ Headers,
Timeout,
NotGiven,
Transport,
@@ -21,9 +22,10 @@
)
from ._utils import is_given, get_async_library
from ._compat import cached_property
+from ._models import SecurityOptions
from ._version import __version__
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
-from ._exceptions import DedalusError, APIStatusError
+from ._exceptions import APIStatusError
from ._base_client import (
DEFAULT_MAX_RETRIES,
SyncAPIClient,
@@ -31,23 +33,34 @@
)
if TYPE_CHECKING:
- from .resources import pets, store, users
- from .resources.pets import PetsResource, AsyncPetsResource
- from .resources.users import UsersResource, AsyncUsersResource
- from .resources.store.store import StoreResource, AsyncStoreResource
+ from .resources import workspaces
+ from .resources.workspaces.workspaces import WorkspacesResource, AsyncWorkspacesResource
__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Dedalus", "AsyncDedalus", "Client", "AsyncClient"]
class Dedalus(SyncAPIClient):
# client options
- api_key: str
+ api_key: str | None
+ 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,
*,
api_key: str | None = None,
+ 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,
@@ -68,20 +81,29 @@ def __init__(
) -> None:
"""Construct a new synchronous Dedalus client instance.
- This automatically infers the `api_key` argument from the `PETSTORE_API_KEY` environment variable if it is not provided.
+ This automatically infers the following arguments from their corresponding environment variables if they are not provided:
+ - `api_key` from `DEDALUS_API_KEY`
+ - `x_api_key` from `DEDALUS_X_API_KEY`
+ - `dedalus_org_id` from `DEDALUS_ORG_ID`
"""
if api_key is None:
- api_key = os.environ.get("PETSTORE_API_KEY")
- if api_key is None:
- raise DedalusError(
- "The api_key client option must be set either by passing api_key to the client or by setting the PETSTORE_API_KEY environment variable"
- )
+ api_key = os.environ.get("DEDALUS_API_KEY")
self.api_key = api_key
+ if x_api_key is None:
+ x_api_key = os.environ.get("DEDALUS_X_API_KEY")
+ self.x_api_key = x_api_key
+
+ if dedalus_org_id is None:
+ 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:
- base_url = f"https://petstore3.swagger.io/api/v3"
+ base_url = f"https://dcs.dedaluslabs.ai"
super().__init__(
version=__version__,
@@ -94,26 +116,13 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
- @cached_property
- def pets(self) -> PetsResource:
- """Everything about your Pets"""
- from .resources.pets import PetsResource
-
- return PetsResource(self)
-
- @cached_property
- def store(self) -> StoreResource:
- """Access to Petstore orders"""
- from .resources.store import StoreResource
-
- return StoreResource(self)
+ self._idempotency_header = "Idempotency-Key"
@cached_property
- def users(self) -> UsersResource:
- """Operations about user"""
- from .resources.users import UsersResource
+ def workspaces(self) -> WorkspacesResource:
+ from .resources.workspaces import WorkspacesResource
- return UsersResource(self)
+ return WorkspacesResource(self)
@cached_property
def with_raw_response(self) -> DedalusWithRawResponse:
@@ -128,11 +137,26 @@ def with_streaming_response(self) -> DedalusWithStreamedResponse:
def qs(self) -> Querystring:
return Querystring(array_format="comma")
- @property
@override
- def auth_headers(self) -> dict[str, str]:
+ 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 {}),
+ }
+
+ @property
+ def _api_key_auth(self) -> dict[str, str]:
+ x_api_key = self.x_api_key
+ if x_api_key is None:
+ return {}
+ return {"x-api-key": x_api_key}
+
+ @property
+ def _bearer_auth(self) -> dict[str, str]:
api_key = self.api_key
- return {"api_key": api_key}
+ if api_key is None:
+ return {}
+ return {"Authorization": f"Bearer {api_key}"}
@property
@override
@@ -140,13 +164,29 @@ def default_headers(self) -> dict[str, str | Omit]:
return {
**super().default_headers,
"X-Stainless-Async": "false",
+ "X-Dedalus-Org-Id": self.dedalus_org_id if self.dedalus_org_id is not None else Omit(),
**self._custom_headers,
}
+ @override
+ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None:
+ if headers.get("x-api-key") or isinstance(custom_headers.get("x-api-key"), Omit):
+ return
+
+ if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit):
+ return
+
+ raise TypeError(
+ '"Could not resolve authentication method. Expected either x_api_key or api_key to be set. Or for one of the `x-api-key` or `Authorization` headers to be explicitly omitted"'
+ )
+
def copy(
self,
*,
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,
@@ -181,6 +221,9 @@ def copy(
http_client = http_client or self._client
return self.__class__(
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,
@@ -230,13 +273,26 @@ def _make_status_error(
class AsyncDedalus(AsyncAPIClient):
# client options
- api_key: str
+ api_key: str | None
+ 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,
*,
api_key: str | None = None,
+ 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,
@@ -257,20 +313,29 @@ def __init__(
) -> None:
"""Construct a new async AsyncDedalus client instance.
- This automatically infers the `api_key` argument from the `PETSTORE_API_KEY` environment variable if it is not provided.
+ This automatically infers the following arguments from their corresponding environment variables if they are not provided:
+ - `api_key` from `DEDALUS_API_KEY`
+ - `x_api_key` from `DEDALUS_X_API_KEY`
+ - `dedalus_org_id` from `DEDALUS_ORG_ID`
"""
if api_key is None:
- api_key = os.environ.get("PETSTORE_API_KEY")
- if api_key is None:
- raise DedalusError(
- "The api_key client option must be set either by passing api_key to the client or by setting the PETSTORE_API_KEY environment variable"
- )
+ api_key = os.environ.get("DEDALUS_API_KEY")
self.api_key = api_key
+ if x_api_key is None:
+ x_api_key = os.environ.get("DEDALUS_X_API_KEY")
+ self.x_api_key = x_api_key
+
+ if dedalus_org_id is None:
+ 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:
- base_url = f"https://petstore3.swagger.io/api/v3"
+ base_url = f"https://dcs.dedaluslabs.ai"
super().__init__(
version=__version__,
@@ -283,26 +348,13 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)
- @cached_property
- def pets(self) -> AsyncPetsResource:
- """Everything about your Pets"""
- from .resources.pets import AsyncPetsResource
-
- return AsyncPetsResource(self)
+ self._idempotency_header = "Idempotency-Key"
@cached_property
- def store(self) -> AsyncStoreResource:
- """Access to Petstore orders"""
- from .resources.store import AsyncStoreResource
+ def workspaces(self) -> AsyncWorkspacesResource:
+ from .resources.workspaces import AsyncWorkspacesResource
- return AsyncStoreResource(self)
-
- @cached_property
- def users(self) -> AsyncUsersResource:
- """Operations about user"""
- from .resources.users import AsyncUsersResource
-
- return AsyncUsersResource(self)
+ return AsyncWorkspacesResource(self)
@cached_property
def with_raw_response(self) -> AsyncDedalusWithRawResponse:
@@ -317,11 +369,26 @@ def with_streaming_response(self) -> AsyncDedalusWithStreamedResponse:
def qs(self) -> Querystring:
return Querystring(array_format="comma")
- @property
@override
- def auth_headers(self) -> dict[str, str]:
+ 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 {}),
+ }
+
+ @property
+ def _api_key_auth(self) -> dict[str, str]:
+ x_api_key = self.x_api_key
+ if x_api_key is None:
+ return {}
+ return {"x-api-key": x_api_key}
+
+ @property
+ def _bearer_auth(self) -> dict[str, str]:
api_key = self.api_key
- return {"api_key": api_key}
+ if api_key is None:
+ return {}
+ return {"Authorization": f"Bearer {api_key}"}
@property
@override
@@ -329,13 +396,29 @@ def default_headers(self) -> dict[str, str | Omit]:
return {
**super().default_headers,
"X-Stainless-Async": f"async:{get_async_library()}",
+ "X-Dedalus-Org-Id": self.dedalus_org_id if self.dedalus_org_id is not None else Omit(),
**self._custom_headers,
}
+ @override
+ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None:
+ if headers.get("x-api-key") or isinstance(custom_headers.get("x-api-key"), Omit):
+ return
+
+ if headers.get("Authorization") or isinstance(custom_headers.get("Authorization"), Omit):
+ return
+
+ raise TypeError(
+ '"Could not resolve authentication method. Expected either x_api_key or api_key to be set. Or for one of the `x-api-key` or `Authorization` headers to be explicitly omitted"'
+ )
+
def copy(
self,
*,
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,
@@ -370,6 +453,9 @@ def copy(
http_client = http_client or self._client
return self.__class__(
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,
@@ -424,25 +510,10 @@ def __init__(self, client: Dedalus) -> None:
self._client = client
@cached_property
- def pets(self) -> pets.PetsResourceWithRawResponse:
- """Everything about your Pets"""
- from .resources.pets import PetsResourceWithRawResponse
-
- return PetsResourceWithRawResponse(self._client.pets)
-
- @cached_property
- def store(self) -> store.StoreResourceWithRawResponse:
- """Access to Petstore orders"""
- from .resources.store import StoreResourceWithRawResponse
-
- return StoreResourceWithRawResponse(self._client.store)
-
- @cached_property
- def users(self) -> users.UsersResourceWithRawResponse:
- """Operations about user"""
- from .resources.users import UsersResourceWithRawResponse
+ def workspaces(self) -> workspaces.WorkspacesResourceWithRawResponse:
+ from .resources.workspaces import WorkspacesResourceWithRawResponse
- return UsersResourceWithRawResponse(self._client.users)
+ return WorkspacesResourceWithRawResponse(self._client.workspaces)
class AsyncDedalusWithRawResponse:
@@ -452,25 +523,10 @@ def __init__(self, client: AsyncDedalus) -> None:
self._client = client
@cached_property
- def pets(self) -> pets.AsyncPetsResourceWithRawResponse:
- """Everything about your Pets"""
- from .resources.pets import AsyncPetsResourceWithRawResponse
+ def workspaces(self) -> workspaces.AsyncWorkspacesResourceWithRawResponse:
+ from .resources.workspaces import AsyncWorkspacesResourceWithRawResponse
- return AsyncPetsResourceWithRawResponse(self._client.pets)
-
- @cached_property
- def store(self) -> store.AsyncStoreResourceWithRawResponse:
- """Access to Petstore orders"""
- from .resources.store import AsyncStoreResourceWithRawResponse
-
- return AsyncStoreResourceWithRawResponse(self._client.store)
-
- @cached_property
- def users(self) -> users.AsyncUsersResourceWithRawResponse:
- """Operations about user"""
- from .resources.users import AsyncUsersResourceWithRawResponse
-
- return AsyncUsersResourceWithRawResponse(self._client.users)
+ return AsyncWorkspacesResourceWithRawResponse(self._client.workspaces)
class DedalusWithStreamedResponse:
@@ -480,25 +536,10 @@ def __init__(self, client: Dedalus) -> None:
self._client = client
@cached_property
- def pets(self) -> pets.PetsResourceWithStreamingResponse:
- """Everything about your Pets"""
- from .resources.pets import PetsResourceWithStreamingResponse
-
- return PetsResourceWithStreamingResponse(self._client.pets)
-
- @cached_property
- def store(self) -> store.StoreResourceWithStreamingResponse:
- """Access to Petstore orders"""
- from .resources.store import StoreResourceWithStreamingResponse
+ def workspaces(self) -> workspaces.WorkspacesResourceWithStreamingResponse:
+ from .resources.workspaces import WorkspacesResourceWithStreamingResponse
- return StoreResourceWithStreamingResponse(self._client.store)
-
- @cached_property
- def users(self) -> users.UsersResourceWithStreamingResponse:
- """Operations about user"""
- from .resources.users import UsersResourceWithStreamingResponse
-
- return UsersResourceWithStreamingResponse(self._client.users)
+ return WorkspacesResourceWithStreamingResponse(self._client.workspaces)
class AsyncDedalusWithStreamedResponse:
@@ -508,25 +549,10 @@ def __init__(self, client: AsyncDedalus) -> None:
self._client = client
@cached_property
- def pets(self) -> pets.AsyncPetsResourceWithStreamingResponse:
- """Everything about your Pets"""
- from .resources.pets import AsyncPetsResourceWithStreamingResponse
-
- return AsyncPetsResourceWithStreamingResponse(self._client.pets)
-
- @cached_property
- def store(self) -> store.AsyncStoreResourceWithStreamingResponse:
- """Access to Petstore orders"""
- from .resources.store import AsyncStoreResourceWithStreamingResponse
-
- return AsyncStoreResourceWithStreamingResponse(self._client.store)
-
- @cached_property
- def users(self) -> users.AsyncUsersResourceWithStreamingResponse:
- """Operations about user"""
- from .resources.users import AsyncUsersResourceWithStreamingResponse
+ def workspaces(self) -> workspaces.AsyncWorkspacesResourceWithStreamingResponse:
+ from .resources.workspaces import AsyncWorkspacesResourceWithStreamingResponse
- return AsyncUsersResourceWithStreamingResponse(self._client.users)
+ return AsyncWorkspacesResourceWithStreamingResponse(self._client.workspaces)
Client = Dedalus
diff --git a/src/dedalus/_compat.py b/src/dedalus_sdk/_compat.py
similarity index 96%
rename from src/dedalus/_compat.py
rename to src/dedalus_sdk/_compat.py
index 786ff42..e6690a4 100644
--- a/src/dedalus/_compat.py
+++ b/src/dedalus_sdk/_compat.py
@@ -2,7 +2,7 @@
from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload
from datetime import date, datetime
-from typing_extensions import Self, Literal
+from typing_extensions import Self, Literal, TypedDict
import pydantic
from pydantic.fields import FieldInfo
@@ -131,6 +131,10 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str:
return model.model_dump_json(indent=indent)
+class _ModelDumpKwargs(TypedDict, total=False):
+ by_alias: bool
+
+
def model_dump(
model: pydantic.BaseModel,
*,
@@ -142,6 +146,9 @@ def model_dump(
by_alias: bool | None = None,
) -> dict[str, Any]:
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
+ kwargs: _ModelDumpKwargs = {}
+ if by_alias is not None:
+ kwargs["by_alias"] = by_alias
return model.model_dump(
mode=mode,
exclude=exclude,
@@ -149,7 +156,7 @@ def model_dump(
exclude_defaults=exclude_defaults,
# warnings are not supported in Pydantic v1
warnings=True if PYDANTIC_V1 else warnings,
- by_alias=by_alias,
+ **kwargs,
)
return cast(
"dict[str, Any]",
diff --git a/src/dedalus/_constants.py b/src/dedalus_sdk/_constants.py
similarity index 100%
rename from src/dedalus/_constants.py
rename to src/dedalus_sdk/_constants.py
diff --git a/src/dedalus/_exceptions.py b/src/dedalus_sdk/_exceptions.py
similarity index 100%
rename from src/dedalus/_exceptions.py
rename to src/dedalus_sdk/_exceptions.py
diff --git a/src/dedalus/_files.py b/src/dedalus_sdk/_files.py
similarity index 100%
rename from src/dedalus/_files.py
rename to src/dedalus_sdk/_files.py
diff --git a/src/dedalus/_models.py b/src/dedalus_sdk/_models.py
similarity index 99%
rename from src/dedalus/_models.py
rename to src/dedalus_sdk/_models.py
index 29070e0..b4f251a 100644
--- a/src/dedalus/_models.py
+++ b/src/dedalus_sdk/_models.py
@@ -791,6 +791,11 @@ def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]:
return RootModel[type_] # type: ignore
+class SecurityOptions(TypedDict, total=False):
+ api_key_auth: bool
+ bearer_auth: bool
+
+
class FinalRequestOptionsInput(TypedDict, total=False):
method: Required[str]
url: Required[str]
@@ -804,6 +809,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
json_data: Body
extra_json: AnyMapping
follow_redirects: bool
+ security: SecurityOptions
@final
@@ -818,6 +824,10 @@ class FinalRequestOptions(pydantic.BaseModel):
idempotency_key: Union[str, None] = None
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
follow_redirects: Union[bool, None] = None
+ security: SecurityOptions = {
+ "api_key_auth": True,
+ "bearer_auth": True,
+ }
content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None
# It should be noted that we cannot use `json` here as that would override
diff --git a/src/dedalus/_qs.py b/src/dedalus_sdk/_qs.py
similarity index 100%
rename from src/dedalus/_qs.py
rename to src/dedalus_sdk/_qs.py
diff --git a/src/dedalus/_resource.py b/src/dedalus_sdk/_resource.py
similarity index 100%
rename from src/dedalus/_resource.py
rename to src/dedalus_sdk/_resource.py
diff --git a/src/dedalus/_response.py b/src/dedalus_sdk/_response.py
similarity index 98%
rename from src/dedalus/_response.py
rename to src/dedalus_sdk/_response.py
index 115e0c0..22dc619 100644
--- a/src/dedalus/_response.py
+++ b/src/dedalus_sdk/_response.py
@@ -220,7 +220,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
and not issubclass(origin, BaseModel)
and issubclass(origin, pydantic.BaseModel)
):
- raise TypeError("Pydantic models must subclass our base model type, e.g. `from dedalus import BaseModel`")
+ raise TypeError(
+ "Pydantic models must subclass our base model type, e.g. `from dedalus_sdk import BaseModel`"
+ )
if (
cast_to is not object
@@ -286,7 +288,7 @@ def parse(self, *, to: type[_T] | None = None) -> R | _T:
the `to` argument, e.g.
```py
- from dedalus import BaseModel
+ from dedalus_sdk import BaseModel
class MyModel(BaseModel):
@@ -388,7 +390,7 @@ async def parse(self, *, to: type[_T] | None = None) -> R | _T:
the `to` argument, e.g.
```py
- from dedalus import BaseModel
+ from dedalus_sdk import BaseModel
class MyModel(BaseModel):
@@ -559,7 +561,7 @@ async def stream_to_file(
class MissingStreamClassError(TypeError):
def __init__(self) -> None:
super().__init__(
- "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `dedalus._streaming` for reference",
+ "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `dedalus_sdk._streaming` for reference",
)
diff --git a/src/dedalus/_streaming.py b/src/dedalus_sdk/_streaming.py
similarity index 100%
rename from src/dedalus/_streaming.py
rename to src/dedalus_sdk/_streaming.py
diff --git a/src/dedalus/_types.py b/src/dedalus_sdk/_types.py
similarity index 98%
rename from src/dedalus/_types.py
rename to src/dedalus_sdk/_types.py
index 6f3161c..60d0aaf 100644
--- a/src/dedalus/_types.py
+++ b/src/dedalus_sdk/_types.py
@@ -36,7 +36,7 @@
from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport
if TYPE_CHECKING:
- from ._models import BaseModel
+ from ._models import BaseModel, SecurityOptions
from ._response import APIResponse, AsyncAPIResponse
Transport = BaseTransport
@@ -101,7 +101,7 @@
# This unfortunately means that you will either have
# to import this type and pass it explicitly:
#
-# from dedalus import NoneType
+# from dedalus_sdk import NoneType
# client.get('/foo', cast_to=NoneType)
#
# or build it yourself:
@@ -121,6 +121,7 @@ class RequestOptions(TypedDict, total=False):
extra_json: AnyMapping
idempotency_key: str
follow_redirects: bool
+ security: SecurityOptions
# Sentinel class used until PEP 0661 is accepted
diff --git a/src/dedalus/_utils/__init__.py b/src/dedalus_sdk/_utils/__init__.py
similarity index 100%
rename from src/dedalus/_utils/__init__.py
rename to src/dedalus_sdk/_utils/__init__.py
diff --git a/src/dedalus/_utils/_compat.py b/src/dedalus_sdk/_utils/_compat.py
similarity index 100%
rename from src/dedalus/_utils/_compat.py
rename to src/dedalus_sdk/_utils/_compat.py
diff --git a/src/dedalus/_utils/_datetime_parse.py b/src/dedalus_sdk/_utils/_datetime_parse.py
similarity index 100%
rename from src/dedalus/_utils/_datetime_parse.py
rename to src/dedalus_sdk/_utils/_datetime_parse.py
diff --git a/src/dedalus/_utils/_json.py b/src/dedalus_sdk/_utils/_json.py
similarity index 100%
rename from src/dedalus/_utils/_json.py
rename to src/dedalus_sdk/_utils/_json.py
diff --git a/src/dedalus/_utils/_logs.py b/src/dedalus_sdk/_utils/_logs.py
similarity index 76%
rename from src/dedalus/_utils/_logs.py
rename to src/dedalus_sdk/_utils/_logs.py
index 28564f7..9436776 100644
--- a/src/dedalus/_utils/_logs.py
+++ b/src/dedalus_sdk/_utils/_logs.py
@@ -1,12 +1,12 @@
import os
import logging
-logger: logging.Logger = logging.getLogger("dedalus")
+logger: logging.Logger = logging.getLogger("dedalus_sdk")
httpx_logger: logging.Logger = logging.getLogger("httpx")
def _basic_config() -> None:
- # e.g. [2023-10-05 14:12:26 - dedalus._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK"
+ # e.g. [2023-10-05 14:12:26 - dedalus_sdk._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK"
logging.basicConfig(
format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
diff --git a/src/dedalus/_utils/_proxy.py b/src/dedalus_sdk/_utils/_proxy.py
similarity index 100%
rename from src/dedalus/_utils/_proxy.py
rename to src/dedalus_sdk/_utils/_proxy.py
diff --git a/src/dedalus/_utils/_reflection.py b/src/dedalus_sdk/_utils/_reflection.py
similarity index 100%
rename from src/dedalus/_utils/_reflection.py
rename to src/dedalus_sdk/_utils/_reflection.py
diff --git a/src/dedalus/_utils/_resources_proxy.py b/src/dedalus_sdk/_utils/_resources_proxy.py
similarity index 51%
rename from src/dedalus/_utils/_resources_proxy.py
rename to src/dedalus_sdk/_utils/_resources_proxy.py
index 6b95fda..3295e1f 100644
--- a/src/dedalus/_utils/_resources_proxy.py
+++ b/src/dedalus_sdk/_utils/_resources_proxy.py
@@ -7,17 +7,17 @@
class ResourcesProxy(LazyProxy[Any]):
- """A proxy for the `dedalus.resources` module.
+ """A proxy for the `dedalus_sdk.resources` module.
- This is used so that we can lazily import `dedalus.resources` only when
- needed *and* so that users can just import `dedalus` and reference `dedalus.resources`
+ This is used so that we can lazily import `dedalus_sdk.resources` only when
+ needed *and* so that users can just import `dedalus_sdk` and reference `dedalus_sdk.resources`
"""
@override
def __load__(self) -> Any:
import importlib
- mod = importlib.import_module("dedalus.resources")
+ mod = importlib.import_module("dedalus_sdk.resources")
return mod
diff --git a/src/dedalus/_utils/_streams.py b/src/dedalus_sdk/_utils/_streams.py
similarity index 100%
rename from src/dedalus/_utils/_streams.py
rename to src/dedalus_sdk/_utils/_streams.py
diff --git a/src/dedalus/_utils/_sync.py b/src/dedalus_sdk/_utils/_sync.py
similarity index 100%
rename from src/dedalus/_utils/_sync.py
rename to src/dedalus_sdk/_utils/_sync.py
diff --git a/src/dedalus/_utils/_transform.py b/src/dedalus_sdk/_utils/_transform.py
similarity index 100%
rename from src/dedalus/_utils/_transform.py
rename to src/dedalus_sdk/_utils/_transform.py
diff --git a/src/dedalus/_utils/_typing.py b/src/dedalus_sdk/_utils/_typing.py
similarity index 100%
rename from src/dedalus/_utils/_typing.py
rename to src/dedalus_sdk/_utils/_typing.py
diff --git a/src/dedalus/_utils/_utils.py b/src/dedalus_sdk/_utils/_utils.py
similarity index 100%
rename from src/dedalus/_utils/_utils.py
rename to src/dedalus_sdk/_utils/_utils.py
diff --git a/src/dedalus/_version.py b/src/dedalus_sdk/_version.py
similarity index 53%
rename from src/dedalus/_version.py
rename to src/dedalus_sdk/_version.py
index 453627e..02910e4 100644
--- a/src/dedalus/_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"
-__version__ = "0.0.1"
+__title__ = "dedalus_sdk"
+__version__ = "0.0.1" # x-release-please-version
diff --git a/src/dedalus_sdk/lib/.keep b/src/dedalus_sdk/lib/.keep
new file mode 100644
index 0000000..5e2c99f
--- /dev/null
+++ b/src/dedalus_sdk/lib/.keep
@@ -0,0 +1,4 @@
+File generated from our OpenAPI spec by Stainless.
+
+This directory can be used to store custom files to expand the SDK.
+It is ignored by Stainless code generation and its content (other than this keep file) won't be touched.
\ No newline at end of file
diff --git a/src/dedalus_sdk/pagination.py b/src/dedalus_sdk/pagination.py
new file mode 100644
index 0000000..fcf2049
--- /dev/null
+++ b/src/dedalus_sdk/pagination.py
@@ -0,0 +1,305 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Generic, TypeVar, Optional
+from typing_extensions import override
+
+from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage
+
+__all__ = [
+ "SyncWorkspaceList",
+ "AsyncWorkspaceList",
+ "SyncSSHSessionList",
+ "AsyncSSHSessionList",
+ "SyncExecutionList",
+ "AsyncExecutionList",
+ "SyncExecutionEvents",
+ "AsyncExecutionEvents",
+ "SyncArtifactList",
+ "AsyncArtifactList",
+ "SyncPreviewList",
+ "AsyncPreviewList",
+ "SyncTerminalList",
+ "AsyncTerminalList",
+]
+
+_T = TypeVar("_T")
+
+
+class SyncWorkspaceList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncWorkspaceList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncSSHSessionList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncSSHSessionList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncExecutionList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncExecutionList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncExecutionEvents(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncExecutionEvents(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncArtifactList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncArtifactList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncPreviewList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncPreviewList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class SyncTerminalList(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
+
+
+class AsyncTerminalList(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ items: List[_T]
+ next_cursor: Optional[str] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ items = self.items
+ if not items:
+ return []
+ return items
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ next_cursor = self.next_cursor
+ if not next_cursor:
+ return None
+
+ return PageInfo(params={"cursor": next_cursor})
diff --git a/src/dedalus/py.typed b/src/dedalus_sdk/py.typed
similarity index 100%
rename from src/dedalus/py.typed
rename to src/dedalus_sdk/py.typed
diff --git a/src/dedalus_sdk/resources/__init__.py b/src/dedalus_sdk/resources/__init__.py
new file mode 100644
index 0000000..b897851
--- /dev/null
+++ b/src/dedalus_sdk/resources/__init__.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .workspaces import (
+ WorkspacesResource,
+ AsyncWorkspacesResource,
+ WorkspacesResourceWithRawResponse,
+ AsyncWorkspacesResourceWithRawResponse,
+ WorkspacesResourceWithStreamingResponse,
+ AsyncWorkspacesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "WorkspacesResource",
+ "AsyncWorkspacesResource",
+ "WorkspacesResourceWithRawResponse",
+ "AsyncWorkspacesResourceWithRawResponse",
+ "WorkspacesResourceWithStreamingResponse",
+ "AsyncWorkspacesResourceWithStreamingResponse",
+]
diff --git a/src/dedalus_sdk/resources/workspaces/__init__.py b/src/dedalus_sdk/resources/workspaces/__init__.py
new file mode 100644
index 0000000..c9822e7
--- /dev/null
+++ b/src/dedalus_sdk/resources/workspaces/__init__.py
@@ -0,0 +1,89 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .ssh import (
+ SSHResource,
+ AsyncSSHResource,
+ SSHResourceWithRawResponse,
+ AsyncSSHResourceWithRawResponse,
+ SSHResourceWithStreamingResponse,
+ AsyncSSHResourceWithStreamingResponse,
+)
+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,
+ ExecutionsResourceWithRawResponse,
+ AsyncExecutionsResourceWithRawResponse,
+ ExecutionsResourceWithStreamingResponse,
+ AsyncExecutionsResourceWithStreamingResponse,
+)
+from .workspaces import (
+ WorkspacesResource,
+ AsyncWorkspacesResource,
+ WorkspacesResourceWithRawResponse,
+ AsyncWorkspacesResourceWithRawResponse,
+ WorkspacesResourceWithStreamingResponse,
+ AsyncWorkspacesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "ArtifactsResource",
+ "AsyncArtifactsResource",
+ "ArtifactsResourceWithRawResponse",
+ "AsyncArtifactsResourceWithRawResponse",
+ "ArtifactsResourceWithStreamingResponse",
+ "AsyncArtifactsResourceWithStreamingResponse",
+ "PreviewsResource",
+ "AsyncPreviewsResource",
+ "PreviewsResourceWithRawResponse",
+ "AsyncPreviewsResourceWithRawResponse",
+ "PreviewsResourceWithStreamingResponse",
+ "AsyncPreviewsResourceWithStreamingResponse",
+ "SSHResource",
+ "AsyncSSHResource",
+ "SSHResourceWithRawResponse",
+ "AsyncSSHResourceWithRawResponse",
+ "SSHResourceWithStreamingResponse",
+ "AsyncSSHResourceWithStreamingResponse",
+ "ExecutionsResource",
+ "AsyncExecutionsResource",
+ "ExecutionsResourceWithRawResponse",
+ "AsyncExecutionsResourceWithRawResponse",
+ "ExecutionsResourceWithStreamingResponse",
+ "AsyncExecutionsResourceWithStreamingResponse",
+ "TerminalsResource",
+ "AsyncTerminalsResource",
+ "TerminalsResourceWithRawResponse",
+ "AsyncTerminalsResourceWithRawResponse",
+ "TerminalsResourceWithStreamingResponse",
+ "AsyncTerminalsResourceWithStreamingResponse",
+ "WorkspacesResource",
+ "AsyncWorkspacesResource",
+ "WorkspacesResourceWithRawResponse",
+ "AsyncWorkspacesResourceWithRawResponse",
+ "WorkspacesResourceWithStreamingResponse",
+ "AsyncWorkspacesResourceWithStreamingResponse",
+]
diff --git a/src/dedalus/resources/store/orders.py b/src/dedalus_sdk/resources/workspaces/artifacts.py
similarity index 50%
rename from src/dedalus/resources/store/orders.py
rename to src/dedalus_sdk/resources/workspaces/artifacts.py
index 3b8381f..92de311 100644
--- a/src/dedalus/resources/store/orders.py
+++ b/src/dedalus_sdk/resources/workspaces/artifacts.py
@@ -2,14 +2,10 @@
from __future__ import annotations
-from typing import Union
-from datetime import datetime
-from typing_extensions import Literal
-
import httpx
-from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -18,57 +14,50 @@
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from ...types.store import order_create_params
-from ..._base_client import make_request_options
-from ...types.shared.order import Order
-
-__all__ = ["OrdersResource", "AsyncOrdersResource"]
+from ...pagination import SyncArtifactList, AsyncArtifactList
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.workspaces import artifact_list_params
+from ...types.workspaces.artifact import Artifact
+__all__ = ["ArtifactsResource", "AsyncArtifactsResource"]
-class OrdersResource(SyncAPIResource):
- """Access to Petstore orders"""
+class ArtifactsResource(SyncAPIResource):
@cached_property
- def with_raw_response(self) -> OrdersResourceWithRawResponse:
+ 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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers
"""
- return OrdersResourceWithRawResponse(self)
+ return ArtifactsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> OrdersResourceWithStreamingResponse:
+ 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/stainless-sdks/dedalus-python#with_streaming_response
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response
"""
- return OrdersResourceWithStreamingResponse(self)
+ return ArtifactsResourceWithStreamingResponse(self)
- def create(
+ def retrieve(
self,
+ artifact_id: str,
*,
- id: int | Omit = omit,
- complete: bool | Omit = omit,
- pet_id: int | Omit = omit,
- quantity: int | Omit = omit,
- ship_date: Union[str, datetime] | Omit = omit,
- status: Literal["placed", "approved", "delivered"] | Omit = omit,
+ workspace_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,
- ) -> Order:
+ ) -> Artifact:
"""
- Place a new order in the store
+ Get artifact
Args:
- status: Order Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -77,40 +66,33 @@ def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._post(
- "/store/order",
- body=maybe_transform(
- {
- "id": id,
- "complete": complete,
- "pet_id": pet_id,
- "quantity": quantity,
- "ship_date": ship_date,
- "status": status,
- },
- order_create_params.OrderCreateParams,
- ),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/artifacts/{artifact_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Order,
+ cast_to=Artifact,
)
- def retrieve(
+ def list(
self,
- order_id: int,
+ workspace_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,
- ) -> Order:
- """For valid response try integer IDs with value <= 5 or > 10.
-
- Other values will
- generate exceptions.
+ ) -> SyncArtifactList[Artifact]:
+ """
+ List artifacts
Args:
extra_headers: Send extra headers
@@ -121,29 +103,42 @@ def retrieve(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._get(
- f"/store/order/{order_id}",
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/artifacts",
+ page=SyncArtifactList[Artifact],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ artifact_list_params.ArtifactListParams,
+ ),
),
- cast_to=Order,
+ model=Artifact,
)
def delete(
self,
- order_id: int,
+ artifact_id: str,
*,
+ workspace_id: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """For valid response try integer IDs with value < 1000.
-
- Anything above 1000 or
- nonintegers will generate API errors
+ idempotency_key: str | None = None,
+ ) -> Artifact:
+ """
+ Delete artifact
Args:
extra_headers: Send extra headers
@@ -153,61 +148,62 @@ def delete(
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
"""
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
- f"/store/order/{order_id}",
+ f"/v1/workspaces/{workspace_id}/artifacts/{artifact_id}",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=NoneType,
+ cast_to=Artifact,
)
-class AsyncOrdersResource(AsyncAPIResource):
- """Access to Petstore orders"""
-
+class AsyncArtifactsResource(AsyncAPIResource):
@cached_property
- def with_raw_response(self) -> AsyncOrdersResourceWithRawResponse:
+ 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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers
"""
- return AsyncOrdersResourceWithRawResponse(self)
+ return AsyncArtifactsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> AsyncOrdersResourceWithStreamingResponse:
+ 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/stainless-sdks/dedalus-python#with_streaming_response
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response
"""
- return AsyncOrdersResourceWithStreamingResponse(self)
+ return AsyncArtifactsResourceWithStreamingResponse(self)
- async def create(
+ async def retrieve(
self,
+ artifact_id: str,
*,
- id: int | Omit = omit,
- complete: bool | Omit = omit,
- pet_id: int | Omit = omit,
- quantity: int | Omit = omit,
- ship_date: Union[str, datetime] | Omit = omit,
- status: Literal["placed", "approved", "delivered"] | Omit = omit,
+ workspace_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,
- ) -> Order:
+ ) -> Artifact:
"""
- Place a new order in the store
+ Get artifact
Args:
- status: Order Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -216,40 +212,33 @@ async def create(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._post(
- "/store/order",
- body=await async_maybe_transform(
- {
- "id": id,
- "complete": complete,
- "pet_id": pet_id,
- "quantity": quantity,
- "ship_date": ship_date,
- "status": status,
- },
- order_create_params.OrderCreateParams,
- ),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/artifacts/{artifact_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=Order,
+ cast_to=Artifact,
)
- async def retrieve(
+ def list(
self,
- order_id: int,
+ workspace_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,
- ) -> Order:
- """For valid response try integer IDs with value <= 5 or > 10.
-
- Other values will
- generate exceptions.
+ ) -> AsyncPaginator[Artifact, AsyncArtifactList[Artifact]]:
+ """
+ List artifacts
Args:
extra_headers: Send extra headers
@@ -260,29 +249,42 @@ async def retrieve(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._get(
- f"/store/order/{order_id}",
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/artifacts",
+ page=AsyncArtifactList[Artifact],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ artifact_list_params.ArtifactListParams,
+ ),
),
- cast_to=Order,
+ model=Artifact,
)
async def delete(
self,
- order_id: int,
+ artifact_id: str,
*,
+ workspace_id: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """For valid response try integer IDs with value < 1000.
-
- Anything above 1000 or
- nonintegers will generate API errors
+ idempotency_key: str | None = None,
+ ) -> Artifact:
+ """
+ Delete artifact
Args:
extra_headers: Send extra headers
@@ -292,72 +294,81 @@ async def delete(
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
"""
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
- f"/store/order/{order_id}",
+ f"/v1/workspaces/{workspace_id}/artifacts/{artifact_id}",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=NoneType,
+ cast_to=Artifact,
)
-class OrdersResourceWithRawResponse:
- def __init__(self, orders: OrdersResource) -> None:
- self._orders = orders
+class ArtifactsResourceWithRawResponse:
+ def __init__(self, artifacts: ArtifactsResource) -> None:
+ self._artifacts = artifacts
- self.create = to_raw_response_wrapper(
- orders.create,
- )
self.retrieve = to_raw_response_wrapper(
- orders.retrieve,
+ artifacts.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ artifacts.list,
)
self.delete = to_raw_response_wrapper(
- orders.delete,
+ artifacts.delete,
)
-class AsyncOrdersResourceWithRawResponse:
- def __init__(self, orders: AsyncOrdersResource) -> None:
- self._orders = orders
+class AsyncArtifactsResourceWithRawResponse:
+ def __init__(self, artifacts: AsyncArtifactsResource) -> None:
+ self._artifacts = artifacts
- self.create = async_to_raw_response_wrapper(
- orders.create,
- )
self.retrieve = async_to_raw_response_wrapper(
- orders.retrieve,
+ artifacts.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ artifacts.list,
)
self.delete = async_to_raw_response_wrapper(
- orders.delete,
+ artifacts.delete,
)
-class OrdersResourceWithStreamingResponse:
- def __init__(self, orders: OrdersResource) -> None:
- self._orders = orders
+class ArtifactsResourceWithStreamingResponse:
+ def __init__(self, artifacts: ArtifactsResource) -> None:
+ self._artifacts = artifacts
- self.create = to_streamed_response_wrapper(
- orders.create,
- )
self.retrieve = to_streamed_response_wrapper(
- orders.retrieve,
+ artifacts.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ artifacts.list,
)
self.delete = to_streamed_response_wrapper(
- orders.delete,
+ artifacts.delete,
)
-class AsyncOrdersResourceWithStreamingResponse:
- def __init__(self, orders: AsyncOrdersResource) -> None:
- self._orders = orders
+class AsyncArtifactsResourceWithStreamingResponse:
+ def __init__(self, artifacts: AsyncArtifactsResource) -> None:
+ self._artifacts = artifacts
- self.create = async_to_streamed_response_wrapper(
- orders.create,
- )
self.retrieve = async_to_streamed_response_wrapper(
- orders.retrieve,
+ artifacts.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ artifacts.list,
)
self.delete = async_to_streamed_response_wrapper(
- orders.delete,
+ artifacts.delete,
)
diff --git a/src/dedalus/resources/users.py b/src/dedalus_sdk/resources/workspaces/executions.py
similarity index 50%
rename from src/dedalus/resources/users.py
rename to src/dedalus_sdk/resources/workspaces/executions.py
index 306ec10..69a48d1 100644
--- a/src/dedalus/resources/users.py
+++ b/src/dedalus_sdk/resources/workspaces/executions.py
@@ -2,74 +2,72 @@
from __future__ import annotations
-from typing import Iterable
+from typing import Dict, Optional
import httpx
-from ..types import user_login_params, user_create_params, user_update_params
-from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
-from .._compat import cached_property
-from .._resource import SyncAPIResource, AsyncAPIResource
-from .._response import (
+from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
to_raw_response_wrapper,
to_streamed_response_wrapper,
async_to_raw_response_wrapper,
async_to_streamed_response_wrapper,
)
-from ..types.user import User
-from .._base_client import make_request_options
-from ..types.user_param import UserParam
+from ...pagination import SyncExecutionList, AsyncExecutionList, SyncExecutionEvents, AsyncExecutionEvents
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.workspaces import execution_list_params, execution_create_params, execution_events_params
+from ...types.workspaces.execution import Execution
+from ...types.workspaces.execution_event import ExecutionEvent
+from ...types.workspaces.execution_output import ExecutionOutput
-__all__ = ["UsersResource", "AsyncUsersResource"]
+__all__ = ["ExecutionsResource", "AsyncExecutionsResource"]
-class UsersResource(SyncAPIResource):
- """Operations about user"""
-
+class ExecutionsResource(SyncAPIResource):
@cached_property
- def with_raw_response(self) -> UsersResourceWithRawResponse:
+ def with_raw_response(self) -> ExecutionsResourceWithRawResponse:
"""
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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers
"""
- return UsersResourceWithRawResponse(self)
+ return ExecutionsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> UsersResourceWithStreamingResponse:
+ def with_streaming_response(self) -> ExecutionsResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response
"""
- return UsersResourceWithStreamingResponse(self)
+ return ExecutionsResourceWithStreamingResponse(self)
def create(
self,
+ workspace_id: str,
*,
- id: int | Omit = omit,
- email: str | Omit = omit,
- first_name: str | Omit = omit,
- last_name: str | Omit = omit,
- password: str | Omit = omit,
- phone: str | Omit = omit,
- username: str | Omit = omit,
- user_status: int | Omit = omit,
+ command: Optional[SequenceNotStr[str]],
+ cwd: str | Omit = omit,
+ env: Dict[str, str] | Omit = omit,
+ stdin: str | Omit = omit,
+ timeout_ms: int | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> User:
+ idempotency_key: str | None = None,
+ ) -> Execution:
"""
- This can only be done by the logged in user.
+ Create execution
Args:
- user_status: User Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -77,41 +75,48 @@ def create(
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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
return self._post(
- "/user",
+ f"/v1/workspaces/{workspace_id}/executions",
body=maybe_transform(
{
- "id": id,
- "email": email,
- "first_name": first_name,
- "last_name": last_name,
- "password": password,
- "phone": phone,
- "username": username,
- "user_status": user_status,
+ "command": command,
+ "cwd": cwd,
+ "env": env,
+ "stdin": stdin,
+ "timeout_ms": timeout_ms,
+ "wake_if_needed": wake_if_needed,
},
- user_create_params.UserCreateParams,
+ execution_create_params.ExecutionCreateParams,
),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=User,
+ cast_to=Execution,
)
def retrieve(
self,
- username: str,
+ execution_id: str,
*,
+ workspace_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,
- ) -> User:
+ ) -> Execution:
"""
- Get user by user name
+ Get execution
Args:
extra_headers: Send extra headers
@@ -122,41 +127,35 @@ def retrieve(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not username:
- raise ValueError(f"Expected a non-empty value for `username` but received {username!r}")
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._get(
- f"/user/{username}",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=User,
+ cast_to=Execution,
)
- def update(
+ def list(
self,
- existing_username: str,
+ workspace_id: str,
*,
- id: int | Omit = omit,
- email: str | Omit = omit,
- first_name: str | Omit = omit,
- last_name: str | Omit = omit,
- password: str | Omit = omit,
- phone: str | Omit = omit,
- username: str | Omit = omit,
- user_status: int | Omit = omit,
+ 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,
- ) -> None:
+ ) -> SyncExecutionList[Execution]:
"""
- This can only be done by the logged in user.
+ List executions
Args:
- user_status: User Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -165,43 +164,42 @@ def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not existing_username:
- raise ValueError(f"Expected a non-empty value for `existing_username` but received {existing_username!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._put(
- f"/user/{existing_username}",
- body=maybe_transform(
- {
- "id": id,
- "email": email,
- "first_name": first_name,
- "last_name": last_name,
- "password": password,
- "phone": phone,
- "username": username,
- "user_status": user_status,
- },
- user_update_params.UserUpdateParams,
- ),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/executions",
+ page=SyncExecutionList[Execution],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ execution_list_params.ExecutionListParams,
+ ),
),
- cast_to=NoneType,
+ model=Execution,
)
def delete(
self,
- username: str,
+ execution_id: str,
*,
+ workspace_id: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
+ idempotency_key: str | None = None,
+ ) -> Execution:
"""
- This can only be done by the logged in user.
+ Delete execution
Args:
extra_headers: Send extra headers
@@ -211,31 +209,41 @@ def delete(
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 username:
- raise ValueError(f"Expected a non-empty value for `username` but received {username!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._delete(
- f"/user/{username}",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=NoneType,
+ cast_to=Execution,
)
- def create_with_list(
+ def events(
self,
+ execution_id: str,
*,
- items: Iterable[UserParam] | Omit = omit,
+ workspace_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,
- ) -> User:
+ ) -> SyncExecutionEvents[ExecutionEvent]:
"""
- Creates list of users with given input array
+ List execution events
Args:
extra_headers: Send extra headers
@@ -246,35 +254,45 @@ def create_with_list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return self._post(
- "/user/createWithList",
- body=maybe_transform(items, Iterable[UserParam]),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}/events",
+ page=SyncExecutionEvents[ExecutionEvent],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ execution_events_params.ExecutionEventsParams,
+ ),
),
- cast_to=User,
+ model=ExecutionEvent,
)
- def login(
+ def output(
self,
+ execution_id: str,
*,
- password: str | Omit = omit,
- username: str | Omit = omit,
+ workspace_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,
- ) -> str:
+ ) -> ExecutionOutput:
"""
- Logs user into the system
+ Get execution output
Args:
- password: The password for login in clear text
-
- username: The user name for login
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -283,91 +301,61 @@ def login(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._get(
- "/user/login",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=maybe_transform(
- {
- "password": password,
- "username": username,
- },
- user_login_params.UserLoginParams,
- ),
- ),
- cast_to=str,
- )
-
- def logout(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Logs out current logged in user session"""
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._get(
- "/user/logout",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}/output",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=NoneType,
+ cast_to=ExecutionOutput,
)
-class AsyncUsersResource(AsyncAPIResource):
- """Operations about user"""
-
+class AsyncExecutionsResource(AsyncAPIResource):
@cached_property
- def with_raw_response(self) -> AsyncUsersResourceWithRawResponse:
+ def with_raw_response(self) -> AsyncExecutionsResourceWithRawResponse:
"""
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/stainless-sdks/dedalus-python#accessing-raw-response-data-eg-headers
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers
"""
- return AsyncUsersResourceWithRawResponse(self)
+ return AsyncExecutionsResourceWithRawResponse(self)
@cached_property
- def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse:
+ def with_streaming_response(self) -> AsyncExecutionsResourceWithStreamingResponse:
"""
An alternative to `.with_raw_response` that doesn't eagerly read the response body.
- For more information, see https://www.github.com/stainless-sdks/dedalus-python#with_streaming_response
+ For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response
"""
- return AsyncUsersResourceWithStreamingResponse(self)
+ return AsyncExecutionsResourceWithStreamingResponse(self)
async def create(
self,
+ workspace_id: str,
*,
- id: int | Omit = omit,
- email: str | Omit = omit,
- first_name: str | Omit = omit,
- last_name: str | Omit = omit,
- password: str | Omit = omit,
- phone: str | Omit = omit,
- username: str | Omit = omit,
- user_status: int | Omit = omit,
+ command: Optional[SequenceNotStr[str]],
+ cwd: str | Omit = omit,
+ env: Dict[str, str] | Omit = omit,
+ stdin: str | Omit = omit,
+ timeout_ms: int | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> User:
+ idempotency_key: str | None = None,
+ ) -> Execution:
"""
- This can only be done by the logged in user.
+ Create execution
Args:
- user_status: User Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -375,41 +363,48 @@ async def create(
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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
return await self._post(
- "/user",
+ f"/v1/workspaces/{workspace_id}/executions",
body=await async_maybe_transform(
{
- "id": id,
- "email": email,
- "first_name": first_name,
- "last_name": last_name,
- "password": password,
- "phone": phone,
- "username": username,
- "user_status": user_status,
+ "command": command,
+ "cwd": cwd,
+ "env": env,
+ "stdin": stdin,
+ "timeout_ms": timeout_ms,
+ "wake_if_needed": wake_if_needed,
},
- user_create_params.UserCreateParams,
+ execution_create_params.ExecutionCreateParams,
),
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=User,
+ cast_to=Execution,
)
async def retrieve(
self,
- username: str,
+ execution_id: str,
*,
+ workspace_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,
- ) -> User:
+ ) -> Execution:
"""
- Get user by user name
+ Get execution
Args:
extra_headers: Send extra headers
@@ -420,41 +415,35 @@ async def retrieve(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not username:
- raise ValueError(f"Expected a non-empty value for `username` but received {username!r}")
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._get(
- f"/user/{username}",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=User,
+ cast_to=Execution,
)
- async def update(
+ def list(
self,
- existing_username: str,
+ workspace_id: str,
*,
- id: int | Omit = omit,
- email: str | Omit = omit,
- first_name: str | Omit = omit,
- last_name: str | Omit = omit,
- password: str | Omit = omit,
- phone: str | Omit = omit,
- username: str | Omit = omit,
- user_status: int | Omit = omit,
+ 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,
- ) -> None:
+ ) -> AsyncPaginator[Execution, AsyncExecutionList[Execution]]:
"""
- This can only be done by the logged in user.
+ List executions
Args:
- user_status: User Status
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -463,43 +452,42 @@ async def update(
timeout: Override the client-level default timeout for this request, in seconds
"""
- if not existing_username:
- raise ValueError(f"Expected a non-empty value for `existing_username` but received {existing_username!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._put(
- f"/user/{existing_username}",
- body=await async_maybe_transform(
- {
- "id": id,
- "email": email,
- "first_name": first_name,
- "last_name": last_name,
- "password": password,
- "phone": phone,
- "username": username,
- "user_status": user_status,
- },
- user_update_params.UserUpdateParams,
- ),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/executions",
+ page=AsyncExecutionList[Execution],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ execution_list_params.ExecutionListParams,
+ ),
),
- cast_to=NoneType,
+ model=Execution,
)
async def delete(
self,
- username: str,
+ execution_id: str,
*,
+ workspace_id: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
+ idempotency_key: str | None = None,
+ ) -> Execution:
"""
- This can only be done by the logged in user.
+ Delete execution
Args:
extra_headers: Send extra headers
@@ -509,31 +497,41 @@ async def delete(
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 username:
- raise ValueError(f"Expected a non-empty value for `username` but received {username!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._delete(
- f"/user/{username}",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}",
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
),
- cast_to=NoneType,
+ cast_to=Execution,
)
- async def create_with_list(
+ def events(
self,
+ execution_id: str,
*,
- items: Iterable[UserParam] | Omit = omit,
+ workspace_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,
- ) -> User:
+ ) -> AsyncPaginator[ExecutionEvent, AsyncExecutionEvents[ExecutionEvent]]:
"""
- Creates list of users with given input array
+ List execution events
Args:
extra_headers: Send extra headers
@@ -544,35 +542,45 @@ async def create_with_list(
timeout: Override the client-level default timeout for this request, in seconds
"""
- return await self._post(
- "/user/createWithList",
- body=await async_maybe_transform(items, Iterable[UserParam]),
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}/events",
+ page=AsyncExecutionEvents[ExecutionEvent],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "cursor": cursor,
+ "limit": limit,
+ },
+ execution_events_params.ExecutionEventsParams,
+ ),
),
- cast_to=User,
+ model=ExecutionEvent,
)
- async def login(
+ async def output(
self,
+ execution_id: str,
*,
- password: str | Omit = omit,
- username: str | Omit = omit,
+ workspace_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,
- ) -> str:
+ ) -> ExecutionOutput:
"""
- Logs user into the system
+ Get execution output
Args:
- password: The password for login in clear text
-
- username: The user name for login
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -581,148 +589,110 @@ async def login(
timeout: Override the client-level default timeout for this request, in seconds
"""
+ if not workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not execution_id:
+ raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._get(
- "/user/login",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {
- "password": password,
- "username": username,
- },
- user_login_params.UserLoginParams,
- ),
- ),
- cast_to=str,
- )
-
- async def logout(
- self,
- *,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Logs out current logged in user session"""
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._get(
- "/user/logout",
+ f"/v1/workspaces/{workspace_id}/executions/{execution_id}/output",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=NoneType,
+ cast_to=ExecutionOutput,
)
-class UsersResourceWithRawResponse:
- def __init__(self, users: UsersResource) -> None:
- self._users = users
+class ExecutionsResourceWithRawResponse:
+ def __init__(self, executions: ExecutionsResource) -> None:
+ self._executions = executions
self.create = to_raw_response_wrapper(
- users.create,
+ executions.create,
)
self.retrieve = to_raw_response_wrapper(
- users.retrieve,
+ executions.retrieve,
)
- self.update = to_raw_response_wrapper(
- users.update,
+ self.list = to_raw_response_wrapper(
+ executions.list,
)
self.delete = to_raw_response_wrapper(
- users.delete,
- )
- self.create_with_list = to_raw_response_wrapper(
- users.create_with_list,
+ executions.delete,
)
- self.login = to_raw_response_wrapper(
- users.login,
+ self.events = to_raw_response_wrapper(
+ executions.events,
)
- self.logout = to_raw_response_wrapper(
- users.logout,
+ self.output = to_raw_response_wrapper(
+ executions.output,
)
-class AsyncUsersResourceWithRawResponse:
- def __init__(self, users: AsyncUsersResource) -> None:
- self._users = users
+class AsyncExecutionsResourceWithRawResponse:
+ def __init__(self, executions: AsyncExecutionsResource) -> None:
+ self._executions = executions
self.create = async_to_raw_response_wrapper(
- users.create,
+ executions.create,
)
self.retrieve = async_to_raw_response_wrapper(
- users.retrieve,
+ executions.retrieve,
)
- self.update = async_to_raw_response_wrapper(
- users.update,
+ self.list = async_to_raw_response_wrapper(
+ executions.list,
)
self.delete = async_to_raw_response_wrapper(
- users.delete,
+ executions.delete,
)
- self.create_with_list = async_to_raw_response_wrapper(
- users.create_with_list,
+ self.events = async_to_raw_response_wrapper(
+ executions.events,
)
- self.login = async_to_raw_response_wrapper(
- users.login,
- )
- self.logout = async_to_raw_response_wrapper(
- users.logout,
+ self.output = async_to_raw_response_wrapper(
+ executions.output,
)
-class UsersResourceWithStreamingResponse:
- def __init__(self, users: UsersResource) -> None:
- self._users = users
+class ExecutionsResourceWithStreamingResponse:
+ def __init__(self, executions: ExecutionsResource) -> None:
+ self._executions = executions
self.create = to_streamed_response_wrapper(
- users.create,
+ executions.create,
)
self.retrieve = to_streamed_response_wrapper(
- users.retrieve,
+ executions.retrieve,
)
- self.update = to_streamed_response_wrapper(
- users.update,
+ self.list = to_streamed_response_wrapper(
+ executions.list,
)
self.delete = to_streamed_response_wrapper(
- users.delete,
- )
- self.create_with_list = to_streamed_response_wrapper(
- users.create_with_list,
+ executions.delete,
)
- self.login = to_streamed_response_wrapper(
- users.login,
+ self.events = to_streamed_response_wrapper(
+ executions.events,
)
- self.logout = to_streamed_response_wrapper(
- users.logout,
+ self.output = to_streamed_response_wrapper(
+ executions.output,
)
-class AsyncUsersResourceWithStreamingResponse:
- def __init__(self, users: AsyncUsersResource) -> None:
- self._users = users
+class AsyncExecutionsResourceWithStreamingResponse:
+ def __init__(self, executions: AsyncExecutionsResource) -> None:
+ self._executions = executions
self.create = async_to_streamed_response_wrapper(
- users.create,
+ executions.create,
)
self.retrieve = async_to_streamed_response_wrapper(
- users.retrieve,
+ executions.retrieve,
)
- self.update = async_to_streamed_response_wrapper(
- users.update,
+ self.list = async_to_streamed_response_wrapper(
+ executions.list,
)
self.delete = async_to_streamed_response_wrapper(
- users.delete,
- )
- self.create_with_list = async_to_streamed_response_wrapper(
- users.create_with_list,
+ executions.delete,
)
- self.login = async_to_streamed_response_wrapper(
- users.login,
+ self.events = async_to_streamed_response_wrapper(
+ executions.events,
)
- self.logout = async_to_streamed_response_wrapper(
- users.logout,
+ self.output = async_to_streamed_response_wrapper(
+ executions.output,
)
diff --git a/src/dedalus_sdk/resources/workspaces/previews.py b/src/dedalus_sdk/resources/workspaces/previews.py
new file mode 100644
index 0000000..6f38dae
--- /dev/null
+++ b/src/dedalus_sdk/resources/workspaces/previews.py
@@ -0,0 +1,490 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ...pagination import SyncPreviewList, AsyncPreviewList
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.workspaces import preview_list_params, preview_create_params
+from ...types.workspaces.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,
+ workspace_id: str,
+ *,
+ port: int,
+ protocol: Literal["http", "https"] | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._post(
+ f"/v1/workspaces/{workspace_id}/previews",
+ body=maybe_transform(
+ {
+ "port": port,
+ "protocol": protocol,
+ "wake_if_needed": wake_if_needed,
+ },
+ 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,
+ preview_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/previews/{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,
+ workspace_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,
+ ) -> SyncPreviewList[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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/previews",
+ page=SyncPreviewList[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,
+ preview_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/previews/{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,
+ workspace_id: str,
+ *,
+ port: int,
+ protocol: Literal["http", "https"] | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return await self._post(
+ f"/v1/workspaces/{workspace_id}/previews",
+ body=await async_maybe_transform(
+ {
+ "port": port,
+ "protocol": protocol,
+ "wake_if_needed": wake_if_needed,
+ },
+ 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,
+ preview_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/previews/{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,
+ workspace_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, AsyncPreviewList[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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/previews",
+ page=AsyncPreviewList[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,
+ preview_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/previews/{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/workspaces/ssh.py b/src/dedalus_sdk/resources/workspaces/ssh.py
new file mode 100644
index 0000000..9cf849b
--- /dev/null
+++ b/src/dedalus_sdk/resources/workspaces/ssh.py
@@ -0,0 +1,484 @@
+# 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 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 SyncSSHSessionList, AsyncSSHSessionList
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.workspaces import ssh_list_params, ssh_create_params
+from ...types.workspaces.ssh_session import SSHSession
+
+__all__ = ["SSHResource", "AsyncSSHResource"]
+
+
+class SSHResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SSHResourceWithRawResponse:
+ """
+ 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 SSHResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SSHResourceWithStreamingResponse:
+ """
+ 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 SSHResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ workspace_id: str,
+ *,
+ public_key: str,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> SSHSession:
+ """
+ Create SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._post(
+ f"/v1/workspaces/{workspace_id}/ssh",
+ body=maybe_transform(
+ {
+ "public_key": public_key,
+ "wake_if_needed": wake_if_needed,
+ },
+ ssh_create_params.SSHCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=SSHSession,
+ )
+
+ def retrieve(
+ self,
+ session_id: str,
+ *,
+ workspace_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,
+ ) -> SSHSession:
+ """
+ Get SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not session_id:
+ raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}")
+ return self._get(
+ f"/v1/workspaces/{workspace_id}/ssh/{session_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SSHSession,
+ )
+
+ def list(
+ self,
+ workspace_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,
+ ) -> SyncSSHSessionList[SSHSession]:
+ """
+ List SSH sessions
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/ssh",
+ page=SyncSSHSessionList[SSHSession],
+ 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,
+ },
+ ssh_list_params.SSHListParams,
+ ),
+ ),
+ model=SSHSession,
+ )
+
+ def delete(
+ self,
+ session_id: str,
+ *,
+ workspace_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,
+ ) -> SSHSession:
+ """
+ Delete SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not session_id:
+ raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}")
+ return self._delete(
+ f"/v1/workspaces/{workspace_id}/ssh/{session_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=SSHSession,
+ )
+
+
+class AsyncSSHResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSSHResourceWithRawResponse:
+ """
+ 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 AsyncSSHResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSSHResourceWithStreamingResponse:
+ """
+ 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 AsyncSSHResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ workspace_id: str,
+ *,
+ public_key: str,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> SSHSession:
+ """
+ Create SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return await self._post(
+ f"/v1/workspaces/{workspace_id}/ssh",
+ body=await async_maybe_transform(
+ {
+ "public_key": public_key,
+ "wake_if_needed": wake_if_needed,
+ },
+ ssh_create_params.SSHCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=SSHSession,
+ )
+
+ async def retrieve(
+ self,
+ session_id: str,
+ *,
+ workspace_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,
+ ) -> SSHSession:
+ """
+ Get SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not session_id:
+ raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}")
+ return await self._get(
+ f"/v1/workspaces/{workspace_id}/ssh/{session_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SSHSession,
+ )
+
+ def list(
+ self,
+ workspace_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[SSHSession, AsyncSSHSessionList[SSHSession]]:
+ """
+ List SSH sessions
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/ssh",
+ page=AsyncSSHSessionList[SSHSession],
+ 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,
+ },
+ ssh_list_params.SSHListParams,
+ ),
+ ),
+ model=SSHSession,
+ )
+
+ async def delete(
+ self,
+ session_id: str,
+ *,
+ workspace_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,
+ ) -> SSHSession:
+ """
+ Delete SSH session
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ if not session_id:
+ raise ValueError(f"Expected a non-empty value for `session_id` but received {session_id!r}")
+ return await self._delete(
+ f"/v1/workspaces/{workspace_id}/ssh/{session_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=SSHSession,
+ )
+
+
+class SSHResourceWithRawResponse:
+ def __init__(self, ssh: SSHResource) -> None:
+ self._ssh = ssh
+
+ self.create = to_raw_response_wrapper(
+ ssh.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ ssh.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ ssh.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ ssh.delete,
+ )
+
+
+class AsyncSSHResourceWithRawResponse:
+ def __init__(self, ssh: AsyncSSHResource) -> None:
+ self._ssh = ssh
+
+ self.create = async_to_raw_response_wrapper(
+ ssh.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ ssh.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ ssh.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ ssh.delete,
+ )
+
+
+class SSHResourceWithStreamingResponse:
+ def __init__(self, ssh: SSHResource) -> None:
+ self._ssh = ssh
+
+ self.create = to_streamed_response_wrapper(
+ ssh.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ ssh.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ ssh.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ ssh.delete,
+ )
+
+
+class AsyncSSHResourceWithStreamingResponse:
+ def __init__(self, ssh: AsyncSSHResource) -> None:
+ self._ssh = ssh
+
+ self.create = async_to_streamed_response_wrapper(
+ ssh.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ ssh.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ ssh.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ ssh.delete,
+ )
diff --git a/src/dedalus_sdk/resources/workspaces/terminals.py b/src/dedalus_sdk/resources/workspaces/terminals.py
new file mode 100644
index 0000000..a30cac6
--- /dev/null
+++ b/src/dedalus_sdk/resources/workspaces/terminals.py
@@ -0,0 +1,873 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import json
+import logging
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Dict, Iterator, 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 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 SyncTerminalList, AsyncTerminalList
+from ..._exceptions import DedalusError
+from ..._base_client import AsyncPaginator, _merge_mappings, make_request_options
+from ...types.workspaces import terminal_list_params, terminal_create_params
+from ...types.workspaces.terminal import Terminal
+from ...types.websocket_connection_options import WebSocketConnectionOptions
+from ...types.workspaces.terminal_client_event import TerminalClientEvent
+from ...types.workspaces.terminal_server_event import TerminalServerEvent
+from ...types.workspaces.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,
+ workspace_id: str,
+ *,
+ height: int,
+ width: int,
+ cwd: str | Omit = omit,
+ env: Dict[str, str] | Omit = omit,
+ shell: str | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._post(
+ f"/v1/workspaces/{workspace_id}/terminals",
+ body=maybe_transform(
+ {
+ "height": height,
+ "width": width,
+ "cwd": cwd,
+ "env": env,
+ "shell": shell,
+ "wake_if_needed": wake_if_needed,
+ },
+ 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,
+ terminal_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/terminals/{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,
+ workspace_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,
+ ) -> SyncTerminalList[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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/terminals",
+ page=SyncTerminalList[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,
+ terminal_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/terminals/{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,
+ extra_query: Query = {},
+ extra_headers: Headers = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
+ ) -> TerminalsResourceConnectionManager:
+ return TerminalsResourceConnectionManager(
+ client=self._client,
+ extra_query=extra_query,
+ extra_headers=extra_headers,
+ websocket_connection_options=websocket_connection_options,
+ )
+
+
+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,
+ workspace_id: str,
+ *,
+ height: int,
+ width: int,
+ cwd: str | Omit = omit,
+ env: Dict[str, str] | Omit = omit,
+ shell: str | Omit = omit,
+ wake_if_needed: bool | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return await self._post(
+ f"/v1/workspaces/{workspace_id}/terminals",
+ body=await async_maybe_transform(
+ {
+ "height": height,
+ "width": width,
+ "cwd": cwd,
+ "env": env,
+ "shell": shell,
+ "wake_if_needed": wake_if_needed,
+ },
+ 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,
+ terminal_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/terminals/{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,
+ workspace_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, AsyncTerminalList[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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get_api_list(
+ f"/v1/workspaces/{workspace_id}/terminals",
+ page=AsyncTerminalList[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,
+ terminal_id: str,
+ *,
+ workspace_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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_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(
+ f"/v1/workspaces/{workspace_id}/terminals/{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,
+ extra_query: Query = {},
+ extra_headers: Headers = {},
+ websocket_connection_options: WebSocketConnectionOptions = {},
+ ) -> AsyncTerminalsResourceConnectionManager:
+ return AsyncTerminalsResourceConnectionManager(
+ client=self._client,
+ extra_query=extra_query,
+ extra_headers=extra_headers,
+ websocket_connection_options=websocket_connection_options,
+ )
+
+
+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) -> None:
+ self._connection = connection
+
+ 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
+
+ try:
+ while True:
+ yield await self.recv()
+ except ConnectionClosedOK:
+ return
+
+ 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))
+ )
+ await self._connection.send(data)
+
+ async def close(self, *, code: int = 1000, reason: str = "") -> None:
+ 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))
+ )
+
+
+class AsyncTerminalsResourceConnectionManager:
+ """
+ Context manager over a `AsyncTerminalsResourceConnection` that is returned by `workspaces.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.workspaces.terminals.connect(...).enter()
+ # ...
+ await connection.close()
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ client: AsyncDedalus,
+ extra_query: Query,
+ extra_headers: Headers,
+ websocket_connection_options: WebSocketConnectionOptions,
+ ) -> None:
+ self.__client = client
+ self.__connection: AsyncTerminalsResourceConnection | None = None
+ self.__extra_query = extra_query
+ self.__extra_headers = extra_headers
+ self.__websocket_connection_options = websocket_connection_options
+
+ 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.workspaces.terminals.connect(...).enter()
+ # ...
+ await connection.close()
+ ```
+ """
+ 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
+
+ url = self._prepare_url().copy_with(
+ params={
+ **self.__client.base_url.params,
+ **self.__extra_query,
+ },
+ )
+ log.debug("Connecting to %s", url)
+ if self.__websocket_connection_options:
+ log.debug("Connection options: %s", self.__websocket_connection_options)
+
+ self.__connection = AsyncTerminalsResourceConnection(
+ await connect(
+ str(url),
+ user_agent_header=self.__client.user_agent,
+ additional_headers=_merge_mappings(
+ {
+ **self.__client.auth_headers,
+ },
+ self.__extra_headers,
+ ),
+ **self.__websocket_connection_options,
+ )
+ )
+
+ return self.__connection
+
+ enter = __aenter__
+
+ 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"/") + b"/v1/workspaces/{workspace_id}/terminals/{terminal_id}/stream"
+ )
+ 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) -> None:
+ self._connection = connection
+
+ def __iter__(self) -> Iterator[TerminalServerEvent]:
+ """
+ An infinite-iterator that will continue to yield events until
+ the connection is closed.
+ """
+ from websockets.exceptions import ConnectionClosedOK
+
+ try:
+ while True:
+ yield self.recv()
+ except ConnectionClosedOK:
+ return
+
+ 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))
+ )
+ self._connection.send(data)
+
+ def close(self, *, code: int = 1000, reason: str = "") -> None:
+ 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))
+ )
+
+
+class TerminalsResourceConnectionManager:
+ """
+ Context manager over a `TerminalsResourceConnection` that is returned by `workspaces.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.workspaces.terminals.connect(...).enter()
+ # ...
+ connection.close()
+ ```
+ """
+
+ def __init__(
+ self,
+ *,
+ client: Dedalus,
+ extra_query: Query,
+ extra_headers: Headers,
+ websocket_connection_options: WebSocketConnectionOptions,
+ ) -> None:
+ self.__client = client
+ self.__connection: TerminalsResourceConnection | None = None
+ self.__extra_query = extra_query
+ self.__extra_headers = extra_headers
+ self.__websocket_connection_options = websocket_connection_options
+
+ 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.workspaces.terminals.connect(...).enter()
+ # ...
+ connection.close()
+ ```
+ """
+ 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
+
+ url = self._prepare_url().copy_with(
+ params={
+ **self.__client.base_url.params,
+ **self.__extra_query,
+ },
+ )
+ log.debug("Connecting to %s", url)
+ if self.__websocket_connection_options:
+ log.debug("Connection options: %s", self.__websocket_connection_options)
+
+ self.__connection = TerminalsResourceConnection(
+ connect(
+ str(url),
+ user_agent_header=self.__client.user_agent,
+ additional_headers=_merge_mappings(
+ {
+ **self.__client.auth_headers,
+ },
+ self.__extra_headers,
+ ),
+ **self.__websocket_connection_options,
+ )
+ )
+
+ return self.__connection
+
+ enter = __enter__
+
+ 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"/") + b"/v1/workspaces/{workspace_id}/terminals/{terminal_id}/stream"
+ )
+ 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/workspaces/workspaces.py b/src/dedalus_sdk/resources/workspaces/workspaces.py
new file mode 100644
index 0000000..624fb67
--- /dev/null
+++ b/src/dedalus_sdk/resources/workspaces/workspaces.py
@@ -0,0 +1,763 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .ssh import (
+ SSHResource,
+ AsyncSSHResource,
+ SSHResourceWithRawResponse,
+ AsyncSSHResourceWithRawResponse,
+ SSHResourceWithStreamingResponse,
+ AsyncSSHResourceWithStreamingResponse,
+)
+from ...types import workspace_list_params, workspace_create_params, workspace_update_params
+from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ..._utils import maybe_transform, async_maybe_transform
+from .previews import (
+ PreviewsResource,
+ AsyncPreviewsResource,
+ PreviewsResourceWithRawResponse,
+ AsyncPreviewsResourceWithRawResponse,
+ PreviewsResourceWithStreamingResponse,
+ AsyncPreviewsResourceWithStreamingResponse,
+)
+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,
+ ExecutionsResourceWithRawResponse,
+ AsyncExecutionsResourceWithRawResponse,
+ ExecutionsResourceWithStreamingResponse,
+ AsyncExecutionsResourceWithStreamingResponse,
+)
+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 SyncWorkspaceList, AsyncWorkspaceList
+from ..._base_client import AsyncPaginator, make_request_options
+from ...types.workspace import Workspace
+from ...types.workspace_list import Item
+
+__all__ = ["WorkspacesResource", "AsyncWorkspacesResource"]
+
+
+class WorkspacesResource(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)
+
+ @cached_property
+ 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) -> WorkspacesResourceWithRawResponse:
+ """
+ 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 WorkspacesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> WorkspacesResourceWithStreamingResponse:
+ """
+ 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 WorkspacesResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ memory_mib: int,
+ storage_gib: int,
+ vcpu: float,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this 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,
+ ) -> Workspace:
+ """
+ Create workspace
+
+ Args:
+ memory_mib: Memory in MiB.
+
+ vcpu: CPU in vCPUs.
+
+ 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
+ """
+ return self._post(
+ "/v1/workspaces",
+ body=maybe_transform(
+ {
+ "memory_mib": memory_mib,
+ "storage_gib": storage_gib,
+ "vcpu": vcpu,
+ },
+ workspace_create_params.WorkspaceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Workspace,
+ )
+
+ def retrieve(
+ self,
+ workspace_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,
+ ) -> Workspace:
+ """
+ Get workspace
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return self._get(
+ f"/v1/workspaces/{workspace_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Workspace,
+ )
+
+ def update(
+ self,
+ workspace_id: str,
+ *,
+ if_match: str,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> Workspace:
+ """
+ Update workspace
+
+ Args:
+ memory_mib: Memory in MiB.
+
+ vcpu: CPU in vCPUs.
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ extra_headers = {"If-Match": if_match, **(extra_headers or {})}
+ return self._patch(
+ f"/v1/workspaces/{workspace_id}",
+ body=maybe_transform(
+ {
+ "memory_mib": memory_mib,
+ "storage_gib": storage_gib,
+ "vcpu": vcpu,
+ },
+ workspace_update_params.WorkspaceUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Workspace,
+ )
+
+ def list(
+ self,
+ *,
+ 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,
+ ) -> SyncWorkspaceList[Item]:
+ """
+ List workspaces
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/v1/workspaces",
+ page=SyncWorkspaceList[Item],
+ 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,
+ },
+ workspace_list_params.WorkspaceListParams,
+ ),
+ ),
+ model=Item,
+ )
+
+ def delete(
+ self,
+ workspace_id: str,
+ *,
+ if_match: 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,
+ ) -> Workspace:
+ """
+ Destroy workspace
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ extra_headers = {"If-Match": if_match, **(extra_headers or {})}
+ return self._delete(
+ f"/v1/workspaces/{workspace_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=Workspace,
+ )
+
+
+class AsyncWorkspacesResource(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)
+
+ @cached_property
+ 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) -> AsyncWorkspacesResourceWithRawResponse:
+ """
+ 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 AsyncWorkspacesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncWorkspacesResourceWithStreamingResponse:
+ """
+ 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 AsyncWorkspacesResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ memory_mib: int,
+ storage_gib: int,
+ vcpu: float,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this 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,
+ ) -> Workspace:
+ """
+ Create workspace
+
+ Args:
+ memory_mib: Memory in MiB.
+
+ vcpu: CPU in vCPUs.
+
+ 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
+ """
+ return await self._post(
+ "/v1/workspaces",
+ body=await async_maybe_transform(
+ {
+ "memory_mib": memory_mib,
+ "storage_gib": storage_gib,
+ "vcpu": vcpu,
+ },
+ workspace_create_params.WorkspaceCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Workspace,
+ )
+
+ async def retrieve(
+ self,
+ workspace_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,
+ ) -> Workspace:
+ """
+ Get workspace
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ return await self._get(
+ f"/v1/workspaces/{workspace_id}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=Workspace,
+ )
+
+ async def update(
+ self,
+ workspace_id: str,
+ *,
+ if_match: str,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ idempotency_key: str | None = None,
+ ) -> Workspace:
+ """
+ Update workspace
+
+ Args:
+ memory_mib: Memory in MiB.
+
+ vcpu: CPU in vCPUs.
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ extra_headers = {"If-Match": if_match, **(extra_headers or {})}
+ return await self._patch(
+ f"/v1/workspaces/{workspace_id}",
+ body=await async_maybe_transform(
+ {
+ "memory_mib": memory_mib,
+ "storage_gib": storage_gib,
+ "vcpu": vcpu,
+ },
+ workspace_update_params.WorkspaceUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=Workspace,
+ )
+
+ def list(
+ self,
+ *,
+ 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[Item, AsyncWorkspaceList[Item]]:
+ """
+ List workspaces
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
+ "/v1/workspaces",
+ page=AsyncWorkspaceList[Item],
+ 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,
+ },
+ workspace_list_params.WorkspaceListParams,
+ ),
+ ),
+ model=Item,
+ )
+
+ async def delete(
+ self,
+ workspace_id: str,
+ *,
+ if_match: 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,
+ ) -> Workspace:
+ """
+ Destroy workspace
+
+ 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 workspace_id:
+ raise ValueError(f"Expected a non-empty value for `workspace_id` but received {workspace_id!r}")
+ extra_headers = {"If-Match": if_match, **(extra_headers or {})}
+ return await self._delete(
+ f"/v1/workspaces/{workspace_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=Workspace,
+ )
+
+
+class WorkspacesResourceWithRawResponse:
+ def __init__(self, workspaces: WorkspacesResource) -> None:
+ self._workspaces = workspaces
+
+ self.create = to_raw_response_wrapper(
+ workspaces.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ workspaces.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ workspaces.update,
+ )
+ self.list = to_raw_response_wrapper(
+ workspaces.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ workspaces.delete,
+ )
+
+ @cached_property
+ def artifacts(self) -> ArtifactsResourceWithRawResponse:
+ return ArtifactsResourceWithRawResponse(self._workspaces.artifacts)
+
+ @cached_property
+ def previews(self) -> PreviewsResourceWithRawResponse:
+ return PreviewsResourceWithRawResponse(self._workspaces.previews)
+
+ @cached_property
+ def ssh(self) -> SSHResourceWithRawResponse:
+ return SSHResourceWithRawResponse(self._workspaces.ssh)
+
+ @cached_property
+ def executions(self) -> ExecutionsResourceWithRawResponse:
+ return ExecutionsResourceWithRawResponse(self._workspaces.executions)
+
+ @cached_property
+ def terminals(self) -> TerminalsResourceWithRawResponse:
+ return TerminalsResourceWithRawResponse(self._workspaces.terminals)
+
+
+class AsyncWorkspacesResourceWithRawResponse:
+ def __init__(self, workspaces: AsyncWorkspacesResource) -> None:
+ self._workspaces = workspaces
+
+ self.create = async_to_raw_response_wrapper(
+ workspaces.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ workspaces.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ workspaces.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ workspaces.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ workspaces.delete,
+ )
+
+ @cached_property
+ def artifacts(self) -> AsyncArtifactsResourceWithRawResponse:
+ return AsyncArtifactsResourceWithRawResponse(self._workspaces.artifacts)
+
+ @cached_property
+ def previews(self) -> AsyncPreviewsResourceWithRawResponse:
+ return AsyncPreviewsResourceWithRawResponse(self._workspaces.previews)
+
+ @cached_property
+ def ssh(self) -> AsyncSSHResourceWithRawResponse:
+ return AsyncSSHResourceWithRawResponse(self._workspaces.ssh)
+
+ @cached_property
+ def executions(self) -> AsyncExecutionsResourceWithRawResponse:
+ return AsyncExecutionsResourceWithRawResponse(self._workspaces.executions)
+
+ @cached_property
+ def terminals(self) -> AsyncTerminalsResourceWithRawResponse:
+ return AsyncTerminalsResourceWithRawResponse(self._workspaces.terminals)
+
+
+class WorkspacesResourceWithStreamingResponse:
+ def __init__(self, workspaces: WorkspacesResource) -> None:
+ self._workspaces = workspaces
+
+ self.create = to_streamed_response_wrapper(
+ workspaces.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ workspaces.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ workspaces.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ workspaces.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ workspaces.delete,
+ )
+
+ @cached_property
+ def artifacts(self) -> ArtifactsResourceWithStreamingResponse:
+ return ArtifactsResourceWithStreamingResponse(self._workspaces.artifacts)
+
+ @cached_property
+ def previews(self) -> PreviewsResourceWithStreamingResponse:
+ return PreviewsResourceWithStreamingResponse(self._workspaces.previews)
+
+ @cached_property
+ def ssh(self) -> SSHResourceWithStreamingResponse:
+ return SSHResourceWithStreamingResponse(self._workspaces.ssh)
+
+ @cached_property
+ def executions(self) -> ExecutionsResourceWithStreamingResponse:
+ return ExecutionsResourceWithStreamingResponse(self._workspaces.executions)
+
+ @cached_property
+ def terminals(self) -> TerminalsResourceWithStreamingResponse:
+ return TerminalsResourceWithStreamingResponse(self._workspaces.terminals)
+
+
+class AsyncWorkspacesResourceWithStreamingResponse:
+ def __init__(self, workspaces: AsyncWorkspacesResource) -> None:
+ self._workspaces = workspaces
+
+ self.create = async_to_streamed_response_wrapper(
+ workspaces.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ workspaces.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ workspaces.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ workspaces.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ workspaces.delete,
+ )
+
+ @cached_property
+ def artifacts(self) -> AsyncArtifactsResourceWithStreamingResponse:
+ return AsyncArtifactsResourceWithStreamingResponse(self._workspaces.artifacts)
+
+ @cached_property
+ def previews(self) -> AsyncPreviewsResourceWithStreamingResponse:
+ return AsyncPreviewsResourceWithStreamingResponse(self._workspaces.previews)
+
+ @cached_property
+ def ssh(self) -> AsyncSSHResourceWithStreamingResponse:
+ return AsyncSSHResourceWithStreamingResponse(self._workspaces.ssh)
+
+ @cached_property
+ def executions(self) -> AsyncExecutionsResourceWithStreamingResponse:
+ return AsyncExecutionsResourceWithStreamingResponse(self._workspaces.executions)
+
+ @cached_property
+ def terminals(self) -> AsyncTerminalsResourceWithStreamingResponse:
+ return AsyncTerminalsResourceWithStreamingResponse(self._workspaces.terminals)
diff --git a/src/dedalus_sdk/types/__init__.py b/src/dedalus_sdk/types/__init__.py
new file mode 100644
index 0000000..2fcb234
--- /dev/null
+++ b/src/dedalus_sdk/types/__init__.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .workspace import Workspace as Workspace
+from .workspace_list import WorkspaceList as WorkspaceList
+from .lifecycle_status import LifecycleStatus as LifecycleStatus
+from .workspace_list_params import WorkspaceListParams as WorkspaceListParams
+from .workspace_create_params import WorkspaceCreateParams as WorkspaceCreateParams
+from .workspace_update_params import WorkspaceUpdateParams as WorkspaceUpdateParams
+from .websocket_connection_options import WebSocketConnectionOptions as WebSocketConnectionOptions
diff --git a/src/dedalus_sdk/types/lifecycle_status.py b/src/dedalus_sdk/types/lifecycle_status.py
new file mode 100644
index 0000000..463b23f
--- /dev/null
+++ b/src/dedalus_sdk/types/lifecycle_status.py
@@ -0,0 +1,35 @@
+# 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__ = ["LifecycleStatus"]
+
+
+class LifecycleStatus(BaseModel):
+ last_progress_at: datetime
+
+ last_transition_at: datetime
+
+ phase: Literal[
+ "accepted",
+ "placement_pending",
+ "starting",
+ "running",
+ "stopping",
+ "sleeping",
+ "destroying",
+ "destroyed",
+ "failed",
+ ]
+
+ reason: str
+
+ retryable: bool
+
+ revision: str
+
+ last_error: Optional[str] = None
diff --git a/src/dedalus_sdk/types/websocket_connection_options.py b/src/dedalus_sdk/types/websocket_connection_options.py
new file mode 100644
index 0000000..36fcfa9
--- /dev/null
+++ b/src/dedalus_sdk/types/websocket_connection_options.py
@@ -0,0 +1,36 @@
+# 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/workspace.py b/src/dedalus_sdk/types/workspace.py
new file mode 100644
index 0000000..79d4842
--- /dev/null
+++ b/src/dedalus_sdk/types/workspace.py
@@ -0,0 +1,30 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+from .lifecycle_status import LifecycleStatus
+
+__all__ = ["Workspace"]
+
+
+class Workspace(BaseModel):
+ desired_state: Literal["active", "inactive", "destroyed"]
+
+ memory_mib: int
+ """Memory in MiB."""
+
+ status: LifecycleStatus
+
+ storage_gib: int
+
+ vcpu: float
+ """CPU in vCPUs."""
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/src/dedalus_sdk/types/workspace_create_params.py b/src/dedalus_sdk/types/workspace_create_params.py
new file mode 100644
index 0000000..a3622e9
--- /dev/null
+++ b/src/dedalus_sdk/types/workspace_create_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["WorkspaceCreateParams"]
+
+
+class WorkspaceCreateParams(TypedDict, total=False):
+ memory_mib: Required[int]
+ """Memory in MiB."""
+
+ storage_gib: Required[int]
+
+ vcpu: Required[float]
+ """CPU in vCPUs."""
diff --git a/src/dedalus_sdk/types/workspace_list.py b/src/dedalus_sdk/types/workspace_list.py
new file mode 100644
index 0000000..3195a84
--- /dev/null
+++ b/src/dedalus_sdk/types/workspace_list.py
@@ -0,0 +1,39 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+from .lifecycle_status import LifecycleStatus
+
+__all__ = ["WorkspaceList", "Item"]
+
+
+class Item(BaseModel):
+ created_at: datetime
+
+ desired_state: Literal["active", "inactive", "destroyed"]
+
+ memory_mib: int
+ """Memory in MiB."""
+
+ status: LifecycleStatus
+
+ storage_gib: int
+
+ vcpu: float
+ """CPU in vCPUs."""
+
+ workspace_id: str
+
+
+class WorkspaceList(BaseModel):
+ items: Optional[List[Item]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspace_list_params.py b/src/dedalus_sdk/types/workspace_list_params.py
new file mode 100644
index 0000000..f3e43d5
--- /dev/null
+++ b/src/dedalus_sdk/types/workspace_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["WorkspaceListParams"]
+
+
+class WorkspaceListParams(TypedDict, total=False):
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspace_update_params.py b/src/dedalus_sdk/types/workspace_update_params.py
new file mode 100644
index 0000000..fdc40d3
--- /dev/null
+++ b/src/dedalus_sdk/types/workspace_update_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["WorkspaceUpdateParams"]
+
+
+class WorkspaceUpdateParams(TypedDict, total=False):
+ if_match: Required[Annotated[str, PropertyInfo(alias="If-Match")]]
+
+ memory_mib: int
+ """Memory in MiB."""
+
+ storage_gib: int
+
+ vcpu: float
+ """CPU in vCPUs."""
diff --git a/src/dedalus_sdk/types/workspaces/__init__.py b/src/dedalus_sdk/types/workspaces/__init__.py
new file mode 100644
index 0000000..56ca47f
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/__init__.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+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
+from .execution_event import ExecutionEvent as ExecutionEvent
+from .ssh_list_params import SSHListParams as SSHListParams
+from .execution_events import ExecutionEvents as ExecutionEvents
+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/workspaces/artifact.py b/src/dedalus_sdk/types/workspaces/artifact.py
new file mode 100644
index 0000000..0119cfa
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/artifact.py
@@ -0,0 +1,35 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["Artifact"]
+
+
+class Artifact(BaseModel):
+ artifact_id: str
+
+ created_at: datetime
+
+ name: str
+
+ size_bytes: int
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ 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/workspaces/artifact_list.py b/src/dedalus_sdk/types/workspaces/artifact_list.py
new file mode 100644
index 0000000..19a2243
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/artifact_list.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .artifact import Artifact
+from ..._models import BaseModel
+
+__all__ = ["ArtifactList"]
+
+
+class ArtifactList(BaseModel):
+ items: Optional[List[Artifact]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/artifact_list_params.py b/src/dedalus_sdk/types/workspaces/artifact_list_params.py
new file mode 100644
index 0000000..514c0f6
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/artifact_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ArtifactListParams"]
+
+
+class ArtifactListParams(TypedDict, total=False):
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/artifact_ref.py b/src/dedalus_sdk/types/workspaces/artifact_ref.py
new file mode 100644
index 0000000..4f31735
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/artifact_ref.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from ..._models import BaseModel
+
+__all__ = ["ArtifactRef"]
+
+
+class ArtifactRef(BaseModel):
+ artifact_id: str
+
+ name: str
diff --git a/src/dedalus_sdk/types/workspaces/execution.py b/src/dedalus_sdk/types/workspaces/execution.py
new file mode 100644
index 0000000..95013b3
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution.py
@@ -0,0 +1,57 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .artifact_ref import ArtifactRef
+
+__all__ = ["Execution"]
+
+
+class Execution(BaseModel):
+ command: Optional[List[str]] = None
+
+ created_at: datetime
+
+ execution_id: str
+
+ status: Literal["wake_in_progress", "queued", "running", "succeeded", "failed", "cancelled", "expired"]
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ artifacts: Optional[List[ArtifactRef]] = None
+
+ completed_at: Optional[datetime] = None
+
+ cwd: Optional[str] = None
+
+ env_keys: Optional[List[str]] = None
+
+ error_code: Optional[str] = None
+
+ error_message: Optional[str] = None
+
+ exit_code: Optional[int] = None
+
+ expires_at: Optional[datetime] = None
+
+ retry_after_ms: Optional[int] = None
+
+ signal: Optional[int] = None
+
+ started_at: Optional[datetime] = None
+
+ stderr_bytes: Optional[int] = None
+
+ stderr_truncated: Optional[bool] = None
+
+ stdout_bytes: Optional[int] = None
+
+ stdout_truncated: Optional[bool] = None
diff --git a/src/dedalus_sdk/types/workspaces/execution_create_params.py b/src/dedalus_sdk/types/workspaces/execution_create_params.py
new file mode 100644
index 0000000..3400720
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_create_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict, Optional
+from typing_extensions import Required, TypedDict
+
+from ..._types import SequenceNotStr
+
+__all__ = ["ExecutionCreateParams"]
+
+
+class ExecutionCreateParams(TypedDict, total=False):
+ command: Required[Optional[SequenceNotStr[str]]]
+
+ cwd: str
+
+ env: Dict[str, str]
+
+ stdin: str
+
+ timeout_ms: int
+
+ wake_if_needed: bool
diff --git a/src/dedalus_sdk/types/workspaces/execution_event.py b/src/dedalus_sdk/types/workspaces/execution_event.py
new file mode 100644
index 0000000..816c3b3
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_event.py
@@ -0,0 +1,31 @@
+# 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__ = ["ExecutionEvent"]
+
+
+class ExecutionEvent(BaseModel):
+ at: datetime
+
+ sequence: int
+
+ type: Literal["lifecycle", "stdout", "stderr"]
+
+ chunk: Optional[str] = None
+
+ error_code: Optional[str] = None
+
+ error_message: Optional[str] = None
+
+ exit_code: Optional[int] = None
+
+ signal: Optional[int] = None
+
+ status: Optional[
+ Literal["wake_in_progress", "queued", "running", "succeeded", "failed", "cancelled", "expired"]
+ ] = None
diff --git a/src/dedalus_sdk/types/workspaces/execution_events.py b/src/dedalus_sdk/types/workspaces/execution_events.py
new file mode 100644
index 0000000..8d167e1
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_events.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .execution_event import ExecutionEvent
+
+__all__ = ["ExecutionEvents"]
+
+
+class ExecutionEvents(BaseModel):
+ items: Optional[List[ExecutionEvent]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/execution_events_params.py b/src/dedalus_sdk/types/workspaces/execution_events_params.py
new file mode 100644
index 0000000..7dcee5c
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_events_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["ExecutionEventsParams"]
+
+
+class ExecutionEventsParams(TypedDict, total=False):
+ workspace_id: Required[str]
+
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/execution_list.py b/src/dedalus_sdk/types/workspaces/execution_list.py
new file mode 100644
index 0000000..0130a8b
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_list.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .execution import Execution
+
+__all__ = ["ExecutionList"]
+
+
+class ExecutionList(BaseModel):
+ items: Optional[List[Execution]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/execution_list_params.py b/src/dedalus_sdk/types/workspaces/execution_list_params.py
new file mode 100644
index 0000000..6c48dfe
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["ExecutionListParams"]
+
+
+class ExecutionListParams(TypedDict, total=False):
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/execution_output.py b/src/dedalus_sdk/types/workspaces/execution_output.py
new file mode 100644
index 0000000..80442f3
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/execution_output.py
@@ -0,0 +1,28 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ExecutionOutput"]
+
+
+class ExecutionOutput(BaseModel):
+ execution_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ stderr: Optional[str] = None
+
+ stderr_bytes: Optional[int] = None
+
+ stderr_truncated: Optional[bool] = None
+
+ stdout: Optional[str] = None
+
+ stdout_bytes: Optional[int] = None
+
+ stdout_truncated: Optional[bool] = None
diff --git a/src/dedalus_sdk/types/workspaces/preview.py b/src/dedalus_sdk/types/workspaces/preview.py
new file mode 100644
index 0000000..f3029ec
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/preview.py
@@ -0,0 +1,40 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["Preview"]
+
+
+class Preview(BaseModel):
+ created_at: datetime
+
+ port: int
+
+ preview_id: str
+
+ status: Literal["wake_in_progress", "ready", "closed", "expired", "failed"]
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ 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/workspaces/preview_create_params.py b/src/dedalus_sdk/types/workspaces/preview_create_params.py
new file mode 100644
index 0000000..3678e00
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/preview_create_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["PreviewCreateParams"]
+
+
+class PreviewCreateParams(TypedDict, total=False):
+ port: Required[int]
+
+ protocol: Literal["http", "https"]
+
+ wake_if_needed: bool
diff --git a/src/dedalus_sdk/types/workspaces/preview_list.py b/src/dedalus_sdk/types/workspaces/preview_list.py
new file mode 100644
index 0000000..1ae136b
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/preview_list.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .preview import Preview
+from ..._models import BaseModel
+
+__all__ = ["PreviewList"]
+
+
+class PreviewList(BaseModel):
+ items: Optional[List[Preview]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/preview_list_params.py b/src/dedalus_sdk/types/workspaces/preview_list_params.py
new file mode 100644
index 0000000..539eb03
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/preview_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["PreviewListParams"]
+
+
+class PreviewListParams(TypedDict, total=False):
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/ssh_connection.py b/src/dedalus_sdk/types/workspaces/ssh_connection.py
new file mode 100644
index 0000000..61919bf
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/ssh_connection.py
@@ -0,0 +1,20 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ..._models import BaseModel
+from .ssh_host_trust import SSHHostTrust
+
+__all__ = ["SSHConnection"]
+
+
+class SSHConnection(BaseModel):
+ endpoint: str
+
+ port: int
+
+ ssh_username: str
+
+ host_trust: Optional[SSHHostTrust] = None
+
+ user_certificate: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/ssh_create_params.py b/src/dedalus_sdk/types/workspaces/ssh_create_params.py
new file mode 100644
index 0000000..ca983af
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/ssh_create_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["SSHCreateParams"]
+
+
+class SSHCreateParams(TypedDict, total=False):
+ public_key: Required[str]
+
+ wake_if_needed: bool
diff --git a/src/dedalus_sdk/types/workspaces/ssh_host_trust.py b/src/dedalus_sdk/types/workspaces/ssh_host_trust.py
new file mode 100644
index 0000000..a7c2db1
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/ssh_host_trust.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["SSHHostTrust"]
+
+
+class SSHHostTrust(BaseModel):
+ host_pattern: str
+
+ kind: Literal["cert_authority"]
+
+ public_key: str
diff --git a/src/dedalus/types/category_param.py b/src/dedalus_sdk/types/workspaces/ssh_list_params.py
similarity index 61%
rename from src/dedalus/types/category_param.py
rename to src/dedalus_sdk/types/workspaces/ssh_list_params.py
index 2cdf264..12be8b6 100644
--- a/src/dedalus/types/category_param.py
+++ b/src/dedalus_sdk/types/workspaces/ssh_list_params.py
@@ -4,10 +4,10 @@
from typing_extensions import TypedDict
-__all__ = ["CategoryParam"]
+__all__ = ["SSHListParams"]
-class CategoryParam(TypedDict, total=False):
- id: int
+class SSHListParams(TypedDict, total=False):
+ cursor: str
- name: str
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/ssh_session.py b/src/dedalus_sdk/types/workspaces/ssh_session.py
new file mode 100644
index 0000000..ebe127e
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/ssh_session.py
@@ -0,0 +1,37 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .ssh_connection import SSHConnection
+
+__all__ = ["SSHSession"]
+
+
+class SSHSession(BaseModel):
+ created_at: datetime
+
+ session_id: str
+
+ status: Literal["wake_in_progress", "ready", "closed", "expired", "failed"]
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ connection: Optional[SSHConnection] = None
+
+ error_code: Optional[str] = None
+
+ error_message: Optional[str] = None
+
+ expires_at: Optional[datetime] = None
+
+ ready_at: Optional[datetime] = None
+
+ retry_after_ms: Optional[int] = None
diff --git a/src/dedalus_sdk/types/workspaces/ssh_session_list.py b/src/dedalus_sdk/types/workspaces/ssh_session_list.py
new file mode 100644
index 0000000..ebf34be
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/ssh_session_list.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+from .ssh_session import SSHSession
+
+__all__ = ["SSHSessionList"]
+
+
+class SSHSessionList(BaseModel):
+ items: Optional[List[SSHSession]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/terminal.py b/src/dedalus_sdk/types/workspaces/terminal.py
new file mode 100644
index 0000000..4812726
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal.py
@@ -0,0 +1,42 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["Terminal"]
+
+
+class Terminal(BaseModel):
+ created_at: datetime
+
+ height: int
+
+ status: Literal["wake_in_progress", "ready", "closed", "expired", "failed"]
+
+ terminal_id: str
+
+ width: int
+
+ workspace_id: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ 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/workspaces/terminal_client_event.py b/src/dedalus_sdk/types/workspaces/terminal_client_event.py
new file mode 100644
index 0000000..94fb770
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_client_event.py
@@ -0,0 +1,14 @@
+# 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/workspaces/terminal_client_event_param.py b/src/dedalus_sdk/types/workspaces/terminal_client_event_param.py
new file mode 100644
index 0000000..d309564
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_client_event_param.py
@@ -0,0 +1,13 @@
+# 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/workspaces/terminal_closed_event.py b/src/dedalus_sdk/types/workspaces/terminal_closed_event.py
new file mode 100644
index 0000000..62c9e93
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_closed_event.py
@@ -0,0 +1,11 @@
+# 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/workspaces/terminal_create_params.py b/src/dedalus_sdk/types/workspaces/terminal_create_params.py
new file mode 100644
index 0000000..09e2cd1
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_create_params.py
@@ -0,0 +1,22 @@
+# 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):
+ height: Required[int]
+
+ width: Required[int]
+
+ cwd: str
+
+ env: Dict[str, str]
+
+ shell: str
+
+ wake_if_needed: bool
diff --git a/src/dedalus_sdk/types/workspaces/terminal_error_event.py b/src/dedalus_sdk/types/workspaces/terminal_error_event.py
new file mode 100644
index 0000000..d1dd0d1
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_error_event.py
@@ -0,0 +1,16 @@
+# 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/workspaces/terminal_input_event.py b/src/dedalus_sdk/types/workspaces/terminal_input_event.py
new file mode 100644
index 0000000..259f896
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_input_event.py
@@ -0,0 +1,14 @@
+# 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/workspaces/terminal_input_event_param.py b/src/dedalus_sdk/types/workspaces/terminal_input_event_param.py
new file mode 100644
index 0000000..17f1984
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_input_event_param.py
@@ -0,0 +1,22 @@
+# 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/workspaces/terminal_list.py b/src/dedalus_sdk/types/workspaces/terminal_list.py
new file mode 100644
index 0000000..4dbf89a
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_list.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from pydantic import Field as FieldInfo
+
+from .terminal import Terminal
+from ..._models import BaseModel
+
+__all__ = ["TerminalList"]
+
+
+class TerminalList(BaseModel):
+ items: Optional[List[Terminal]] = None
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
+
+ next_cursor: Optional[str] = None
diff --git a/src/dedalus_sdk/types/workspaces/terminal_list_params.py b/src/dedalus_sdk/types/workspaces/terminal_list_params.py
new file mode 100644
index 0000000..51deecb
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_list_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["TerminalListParams"]
+
+
+class TerminalListParams(TypedDict, total=False):
+ cursor: str
+
+ limit: int
diff --git a/src/dedalus_sdk/types/workspaces/terminal_output_event.py b/src/dedalus_sdk/types/workspaces/terminal_output_event.py
new file mode 100644
index 0000000..a6fe0c5
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_output_event.py
@@ -0,0 +1,14 @@
+# 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/workspaces/terminal_resize_event.py b/src/dedalus_sdk/types/workspaces/terminal_resize_event.py
new file mode 100644
index 0000000..b69dd07
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_resize_event.py
@@ -0,0 +1,15 @@
+# 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/workspaces/terminal_resize_event_param.py b/src/dedalus_sdk/types/workspaces/terminal_resize_event_param.py
new file mode 100644
index 0000000..3b03e5e
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_resize_event_param.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import 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/workspaces/terminal_server_event.py b/src/dedalus_sdk/types/workspaces/terminal_server_event.py
new file mode 100644
index 0000000..d51df44
--- /dev/null
+++ b/src/dedalus_sdk/types/workspaces/terminal_server_event.py
@@ -0,0 +1,15 @@
+# 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/tests/api_resources/store/test_orders.py b/tests/api_resources/store/test_orders.py
deleted file mode 100644
index 8f6f597..0000000
--- a/tests/api_resources/store/test_orders.py
+++ /dev/null
@@ -1,243 +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 import Dedalus, AsyncDedalus
-from tests.utils import assert_matches_type
-from dedalus._utils import parse_datetime
-from dedalus.types.shared import Order
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestOrders:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create(self, client: Dedalus) -> None:
- order = client.store.orders.create()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Dedalus) -> None:
- order = client.store.orders.create(
- id=10,
- complete=True,
- pet_id=198772,
- quantity=7,
- ship_date=parse_datetime("2019-12-27T18:11:19.117Z"),
- status="approved",
- )
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Dedalus) -> None:
- response = client.store.orders.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Dedalus) -> None:
- with client.store.orders.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_retrieve(self, client: Dedalus) -> None:
- order = client.store.orders.retrieve(
- 0,
- )
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_retrieve(self, client: Dedalus) -> None:
- response = client.store.orders.with_raw_response.retrieve(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_retrieve(self, client: Dedalus) -> None:
- with client.store.orders.with_streaming_response.retrieve(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_delete(self, client: Dedalus) -> None:
- order = client.store.orders.delete(
- 0,
- )
- assert order is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_delete(self, client: Dedalus) -> None:
- response = client.store.orders.with_raw_response.delete(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = response.parse()
- assert order is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_delete(self, client: Dedalus) -> None:
- with client.store.orders.with_streaming_response.delete(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = response.parse()
- assert order is None
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncOrders:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create(self, async_client: AsyncDedalus) -> None:
- order = await async_client.store.orders.create()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None:
- order = await async_client.store.orders.create(
- id=10,
- complete=True,
- pet_id=198772,
- quantity=7,
- ship_date=parse_datetime("2019-12-27T18:11:19.117Z"),
- status="approved",
- )
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
- response = await async_client.store.orders.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = await response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
- async with async_client.store.orders.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = await response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
- order = await async_client.store.orders.retrieve(
- 0,
- )
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
- response = await async_client.store.orders.with_raw_response.retrieve(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = await response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
- async with async_client.store.orders.with_streaming_response.retrieve(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = await response.parse()
- assert_matches_type(Order, order, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_delete(self, async_client: AsyncDedalus) -> None:
- order = await async_client.store.orders.delete(
- 0,
- )
- assert order is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
- response = await async_client.store.orders.with_raw_response.delete(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- order = await response.parse()
- assert order is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
- async with async_client.store.orders.with_streaming_response.delete(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- order = await response.parse()
- assert order is None
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_pets.py b/tests/api_resources/test_pets.py
deleted file mode 100644
index 5f9c1e6..0000000
--- a/tests/api_resources/test_pets.py
+++ /dev/null
@@ -1,723 +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 import Dedalus, AsyncDedalus
-from tests.utils import assert_matches_type
-from dedalus.types import (
- Pet,
- PetFindByTagsResponse,
- PetUploadImageResponse,
- PetFindByStatusResponse,
-)
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestPets:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create(self, client: Dedalus) -> None:
- pet = client.pets.create(
- name="doggie",
- photo_urls=["string"],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.create(
- name="doggie",
- photo_urls=["string"],
- id=10,
- category={
- "id": 1,
- "name": "Dogs",
- },
- status="available",
- tags=[
- {
- "id": 0,
- "name": "name",
- }
- ],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.create(
- name="doggie",
- photo_urls=["string"],
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.create(
- name="doggie",
- photo_urls=["string"],
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_retrieve(self, client: Dedalus) -> None:
- pet = client.pets.retrieve(
- 0,
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_retrieve(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.retrieve(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_retrieve(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.retrieve(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update(self, client: Dedalus) -> None:
- pet = client.pets.update(
- name="doggie",
- photo_urls=["string"],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.update(
- name="doggie",
- photo_urls=["string"],
- id=10,
- category={
- "id": 1,
- "name": "Dogs",
- },
- status="available",
- tags=[
- {
- "id": 0,
- "name": "name",
- }
- ],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_update(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.update(
- name="doggie",
- photo_urls=["string"],
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_update(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.update(
- name="doggie",
- photo_urls=["string"],
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_delete(self, client: Dedalus) -> None:
- pet = client.pets.delete(
- 0,
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_delete(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.delete(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_delete(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.delete(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert pet is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_find_by_status(self, client: Dedalus) -> None:
- pet = client.pets.find_by_status()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_find_by_status_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.find_by_status(
- status="available",
- )
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_find_by_status(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.find_by_status()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_find_by_status(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.find_by_status() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_find_by_tags(self, client: Dedalus) -> None:
- pet = client.pets.find_by_tags()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_find_by_tags_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.find_by_tags(
- tags=["string"],
- )
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_find_by_tags(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.find_by_tags()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_find_by_tags(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.find_by_tags() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update_by_id(self, client: Dedalus) -> None:
- pet = client.pets.update_by_id(
- pet_id=0,
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update_by_id_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.update_by_id(
- pet_id=0,
- name="name",
- status="status",
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_update_by_id(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.update_by_id(
- pet_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_update_by_id(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.update_by_id(
- pet_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert pet is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_upload_image(self, client: Dedalus) -> None:
- pet = client.pets.upload_image(
- pet_id=0,
- image=b"raw file contents",
- )
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_upload_image_with_all_params(self, client: Dedalus) -> None:
- pet = client.pets.upload_image(
- pet_id=0,
- image=b"raw file contents",
- additional_metadata="additionalMetadata",
- )
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_upload_image(self, client: Dedalus) -> None:
- response = client.pets.with_raw_response.upload_image(
- pet_id=0,
- image=b"raw file contents",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = response.parse()
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_upload_image(self, client: Dedalus) -> None:
- with client.pets.with_streaming_response.upload_image(
- pet_id=0,
- image=b"raw file contents",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = response.parse()
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncPets:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.create(
- name="doggie",
- photo_urls=["string"],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.create(
- name="doggie",
- photo_urls=["string"],
- id=10,
- category={
- "id": 1,
- "name": "Dogs",
- },
- status="available",
- tags=[
- {
- "id": 0,
- "name": "name",
- }
- ],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.create(
- name="doggie",
- photo_urls=["string"],
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.create(
- name="doggie",
- photo_urls=["string"],
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.retrieve(
- 0,
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.retrieve(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.retrieve(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.update(
- name="doggie",
- photo_urls=["string"],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.update(
- name="doggie",
- photo_urls=["string"],
- id=10,
- category={
- "id": 1,
- "name": "Dogs",
- },
- status="available",
- tags=[
- {
- "id": 0,
- "name": "name",
- }
- ],
- )
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_update(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.update(
- name="doggie",
- photo_urls=["string"],
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_update(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.update(
- name="doggie",
- photo_urls=["string"],
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(Pet, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_delete(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.delete(
- 0,
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.delete(
- 0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.delete(
- 0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert pet is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_find_by_status(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.find_by_status()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_find_by_status_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.find_by_status(
- status="available",
- )
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_find_by_status(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.find_by_status()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_find_by_status(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.find_by_status() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(PetFindByStatusResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_find_by_tags(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.find_by_tags()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_find_by_tags_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.find_by_tags(
- tags=["string"],
- )
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_find_by_tags(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.find_by_tags()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_find_by_tags(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.find_by_tags() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(PetFindByTagsResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update_by_id(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.update_by_id(
- pet_id=0,
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update_by_id_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.update_by_id(
- pet_id=0,
- name="name",
- status="status",
- )
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_update_by_id(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.update_by_id(
- pet_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert pet is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_update_by_id(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.update_by_id(
- pet_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert pet is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_upload_image(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.upload_image(
- pet_id=0,
- image=b"raw file contents",
- )
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_upload_image_with_all_params(self, async_client: AsyncDedalus) -> None:
- pet = await async_client.pets.upload_image(
- pet_id=0,
- image=b"raw file contents",
- additional_metadata="additionalMetadata",
- )
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_upload_image(self, async_client: AsyncDedalus) -> None:
- response = await async_client.pets.with_raw_response.upload_image(
- pet_id=0,
- image=b"raw file contents",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- pet = await response.parse()
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_upload_image(self, async_client: AsyncDedalus) -> None:
- async with async_client.pets.with_streaming_response.upload_image(
- pet_id=0,
- image=b"raw file contents",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- pet = await response.parse()
- assert_matches_type(PetUploadImageResponse, pet, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_store.py b/tests/api_resources/test_store.py
deleted file mode 100644
index a57e82d..0000000
--- a/tests/api_resources/test_store.py
+++ /dev/null
@@ -1,80 +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 import Dedalus, AsyncDedalus
-from tests.utils import assert_matches_type
-from dedalus.types import StoreListInventoryResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestStore:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_list_inventory(self, client: Dedalus) -> None:
- store = client.store.list_inventory()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_list_inventory(self, client: Dedalus) -> None:
- response = client.store.with_raw_response.list_inventory()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- store = response.parse()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_list_inventory(self, client: Dedalus) -> None:
- with client.store.with_streaming_response.list_inventory() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- store = response.parse()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncStore:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_list_inventory(self, async_client: AsyncDedalus) -> None:
- store = await async_client.store.list_inventory()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_list_inventory(self, async_client: AsyncDedalus) -> None:
- response = await async_client.store.with_raw_response.list_inventory()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- store = await response.parse()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_list_inventory(self, async_client: AsyncDedalus) -> None:
- async with async_client.store.with_streaming_response.list_inventory() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- store = await response.parse()
- assert_matches_type(StoreListInventoryResponse, store, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_users.py b/tests/api_resources/test_users.py
deleted file mode 100644
index 2c5893c..0000000
--- a/tests/api_resources/test_users.py
+++ /dev/null
@@ -1,620 +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 import Dedalus, AsyncDedalus
-from tests.utils import assert_matches_type
-from dedalus.types import (
- User,
-)
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestUsers:
- parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create(self, client: Dedalus) -> None:
- user = client.users.create()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: Dedalus) -> None:
- user = client.users.create(
- id=10,
- email="john@email.com",
- first_name="John",
- last_name="James",
- password="12345",
- phone="12345",
- username="theUser",
- user_status=1,
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_retrieve(self, client: Dedalus) -> None:
- user = client.users.retrieve(
- "username",
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_retrieve(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.retrieve(
- "username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_retrieve(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.retrieve(
- "username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_retrieve(self, client: Dedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"):
- client.users.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update(self, client: Dedalus) -> None:
- user = client.users.update(
- existing_username="username",
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_update_with_all_params(self, client: Dedalus) -> None:
- user = client.users.update(
- existing_username="username",
- id=10,
- email="john@email.com",
- first_name="John",
- last_name="James",
- password="12345",
- phone="12345",
- username="theUser",
- user_status=1,
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_update(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.update(
- existing_username="username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_update(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.update(
- existing_username="username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_update(self, client: Dedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `existing_username` but received ''"):
- client.users.with_raw_response.update(
- existing_username="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_delete(self, client: Dedalus) -> None:
- user = client.users.delete(
- "username",
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_delete(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.delete(
- "username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_delete(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.delete(
- "username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_path_params_delete(self, client: Dedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"):
- client.users.with_raw_response.delete(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_list(self, client: Dedalus) -> None:
- user = client.users.create_with_list()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_list_with_all_params(self, client: Dedalus) -> None:
- user = client.users.create_with_list(
- items=[
- {
- "id": 10,
- "email": "john@email.com",
- "first_name": "John",
- "last_name": "James",
- "password": "12345",
- "phone": "12345",
- "username": "theUser",
- "user_status": 1,
- }
- ],
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_create_with_list(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.create_with_list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_create_with_list(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.create_with_list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_login(self, client: Dedalus) -> None:
- user = client.users.login()
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_login_with_all_params(self, client: Dedalus) -> None:
- user = client.users.login(
- password="password",
- username="username",
- )
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_login(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.login()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_login(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.login() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert_matches_type(str, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_logout(self, client: Dedalus) -> None:
- user = client.users.logout()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_logout(self, client: Dedalus) -> None:
- response = client.users.with_raw_response.logout()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_logout(self, client: Dedalus) -> None:
- with client.users.with_streaming_response.logout() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncUsers:
- parametrize = pytest.mark.parametrize(
- "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.create()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.create(
- id=10,
- email="john@email.com",
- first_name="John",
- last_name="James",
- password="12345",
- phone="12345",
- username="theUser",
- user_status=1,
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.create()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.create() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.retrieve(
- "username",
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.retrieve(
- "username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.retrieve(
- "username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_retrieve(self, async_client: AsyncDedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"):
- await async_client.users.with_raw_response.retrieve(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.update(
- existing_username="username",
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_update_with_all_params(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.update(
- existing_username="username",
- id=10,
- email="john@email.com",
- first_name="John",
- last_name="James",
- password="12345",
- phone="12345",
- username="theUser",
- user_status=1,
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_update(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.update(
- existing_username="username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_update(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.update(
- existing_username="username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_update(self, async_client: AsyncDedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `existing_username` but received ''"):
- await async_client.users.with_raw_response.update(
- existing_username="",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_delete(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.delete(
- "username",
- )
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.delete(
- "username",
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.delete(
- "username",
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_path_params_delete(self, async_client: AsyncDedalus) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `username` but received ''"):
- await async_client.users.with_raw_response.delete(
- "",
- )
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_list(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.create_with_list()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_list_with_all_params(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.create_with_list(
- items=[
- {
- "id": 10,
- "email": "john@email.com",
- "first_name": "John",
- "last_name": "James",
- "password": "12345",
- "phone": "12345",
- "username": "theUser",
- "user_status": 1,
- }
- ],
- )
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_create_with_list(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.create_with_list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_create_with_list(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.create_with_list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert_matches_type(User, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_login(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.login()
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_login_with_all_params(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.login(
- password="password",
- username="username",
- )
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_login(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.login()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert_matches_type(str, user, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_login(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.login() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert_matches_type(str, user, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_logout(self, async_client: AsyncDedalus) -> None:
- user = await async_client.users.logout()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_raw_response_logout(self, async_client: AsyncDedalus) -> None:
- response = await async_client.users.with_raw_response.logout()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- user = await response.parse()
- assert user is None
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_streaming_response_logout(self, async_client: AsyncDedalus) -> None:
- async with async_client.users.with_streaming_response.logout() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- user = await response.parse()
- assert user is None
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_workspaces.py b/tests/api_resources/test_workspaces.py
new file mode 100644
index 0000000..59488d5
--- /dev/null
+++ b/tests/api_resources/test_workspaces.py
@@ -0,0 +1,432 @@
+# 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 Workspace
+from dedalus_sdk.pagination import SyncWorkspaceList, AsyncWorkspaceList
+from dedalus_sdk.types.workspace_list import Item
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestWorkspaces:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Dedalus) -> None:
+ workspace = client.workspaces.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Dedalus) -> None:
+ response = client.workspaces.with_raw_response.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Dedalus) -> None:
+ with client.workspaces.with_streaming_response.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: Dedalus) -> None:
+ workspace = client.workspaces.retrieve(
+ "workspace_id",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.with_raw_response.retrieve(
+ "workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Dedalus) -> None:
+ with client.workspaces.with_streaming_response.retrieve(
+ "workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, 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 `workspace_id` but received ''"):
+ client.workspaces.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_update(self, client: Dedalus) -> None:
+ workspace = client.workspaces.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_method_update_with_all_params(self, client: Dedalus) -> None:
+ workspace = client.workspaces.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: Dedalus) -> None:
+ response = client.workspaces.with_raw_response.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: Dedalus) -> None:
+ with client.workspaces.with_streaming_response.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: Dedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ client.workspaces.with_raw_response.update(
+ workspace_id="",
+ if_match="If-Match",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ workspace = client.workspaces.list()
+ assert_matches_type(SyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ workspace = client.workspaces.list(
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = response.parse()
+ assert_matches_type(SyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = response.parse()
+ assert_matches_type(SyncWorkspaceList[Item], workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ workspace = client.workspaces.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.with_raw_response.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Dedalus) -> None:
+ with client.workspaces.with_streaming_response.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = response.parse()
+ assert_matches_type(Workspace, workspace, 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 `workspace_id` but received ''"):
+ client.workspaces.with_raw_response.delete(
+ workspace_id="",
+ if_match="If-Match",
+ )
+
+
+class TestAsyncWorkspaces:
+ 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:
+ workspace = await async_client.workspaces.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.with_raw_response.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.with_streaming_response.create(
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.retrieve(
+ "workspace_id",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.with_raw_response.retrieve(
+ "workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.with_streaming_response.retrieve(
+ "workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_method_update_with_all_params(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ memory_mib=0,
+ storage_gib=0,
+ vcpu=0,
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.with_raw_response.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.with_streaming_response.update(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncDedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ await async_client.workspaces.with_raw_response.update(
+ workspace_id="",
+ if_match="If-Match",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.list()
+ assert_matches_type(AsyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.list(
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = await response.parse()
+ assert_matches_type(AsyncWorkspaceList[Item], workspace, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = await response.parse()
+ assert_matches_type(AsyncWorkspaceList[Item], workspace, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ workspace = await async_client.workspaces.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.with_raw_response.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.with_streaming_response.delete(
+ workspace_id="workspace_id",
+ if_match="If-Match",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ workspace = await response.parse()
+ assert_matches_type(Workspace, workspace, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.with_raw_response.delete(
+ workspace_id="",
+ if_match="If-Match",
+ )
diff --git a/tests/api_resources/store/__init__.py b/tests/api_resources/workspaces/__init__.py
similarity index 100%
rename from tests/api_resources/store/__init__.py
rename to tests/api_resources/workspaces/__init__.py
diff --git a/tests/api_resources/workspaces/test_artifacts.py b/tests/api_resources/workspaces/test_artifacts.py
new file mode 100644
index 0000000..5922cfd
--- /dev/null
+++ b/tests/api_resources/workspaces/test_artifacts.py
@@ -0,0 +1,311 @@
+# 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 SyncArtifactList, AsyncArtifactList
+from dedalus_sdk.types.workspaces 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.workspaces.artifacts.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Artifact, artifact, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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.workspaces.artifacts.with_streaming_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"):
+ client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ artifact = client.workspaces.artifacts.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ artifact = client.workspaces.artifacts.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.artifacts.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ artifact = response.parse()
+ assert_matches_type(SyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.artifacts.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ artifact = response.parse()
+ assert_matches_type(SyncArtifactList[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 `workspace_id` but received ''"):
+ client.workspaces.artifacts.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ artifact = client.workspaces.artifacts.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Artifact, artifact, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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.workspaces.artifacts.with_streaming_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"):
+ client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="",
+ workspace_id="workspace_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.workspaces.artifacts.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Artifact, artifact, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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.workspaces.artifacts.with_streaming_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="artifact_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"):
+ await async_client.workspaces.artifacts.with_raw_response.retrieve(
+ artifact_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ artifact = await async_client.workspaces.artifacts.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ artifact = await async_client.workspaces.artifacts.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.artifacts.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ artifact = await response.parse()
+ assert_matches_type(AsyncArtifactList[Artifact], artifact, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.artifacts.with_streaming_response.list(
+ workspace_id="workspace_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(AsyncArtifactList[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 `workspace_id` but received ''"):
+ await async_client.workspaces.artifacts.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ artifact = await async_client.workspaces.artifacts.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Artifact, artifact, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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.workspaces.artifacts.with_streaming_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="artifact_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"):
+ await async_client.workspaces.artifacts.with_raw_response.delete(
+ artifact_id="",
+ workspace_id="workspace_id",
+ )
diff --git a/tests/api_resources/workspaces/test_executions.py b/tests/api_resources/workspaces/test_executions.py
new file mode 100644
index 0000000..57cea4e
--- /dev/null
+++ b/tests/api_resources/workspaces/test_executions.py
@@ -0,0 +1,637 @@
+# 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 SyncExecutionList, AsyncExecutionList, SyncExecutionEvents, AsyncExecutionEvents
+from dedalus_sdk.types.workspaces import (
+ Execution,
+ ExecutionEvent,
+ ExecutionOutput,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestExecutions:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ cwd="cwd",
+ env={"foo": "string"},
+ stdin="stdin",
+ timeout_ms=0,
+ wake_if_needed=True,
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.create(
+ workspace_id="",
+ command=["string"],
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(SyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(SyncExecutionList[Execution], execution, 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 `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.delete(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.workspaces.executions.with_raw_response.delete(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_events(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ def test_method_events_with_all_params(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_events(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(SyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_events(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(SyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_events(self, client: Dedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.events(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.workspaces.executions.with_raw_response.events(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_output(self, client: Dedalus) -> None:
+ execution = client.workspaces.executions.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_output(self, client: Dedalus) -> None:
+ response = client.workspaces.executions.with_raw_response.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_output(self, client: Dedalus) -> None:
+ with client.workspaces.executions.with_streaming_response.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_output(self, client: Dedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ client.workspaces.executions.with_raw_response.output(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.workspaces.executions.with_raw_response.output(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+
+class TestAsyncExecutions:
+ 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:
+ execution = await async_client.workspaces.executions.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ cwd="cwd",
+ env={"foo": "string"},
+ stdin="stdin",
+ timeout_ms=0,
+ wake_if_needed=True,
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.create(
+ workspace_id="workspace_id",
+ command=["string"],
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.create(
+ workspace_id="",
+ command=["string"],
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.retrieve(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(AsyncExecutionList[Execution], execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(AsyncExecutionList[Execution], execution, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.delete(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(Execution, execution, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.delete(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.delete(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_events(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ async def test_method_events_with_all_params(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_events(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(AsyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_events(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.events(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(AsyncExecutionEvents[ExecutionEvent], execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_events(self, async_client: AsyncDedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.events(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.events(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_output(self, async_client: AsyncDedalus) -> None:
+ execution = await async_client.workspaces.executions.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_output(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.executions.with_raw_response.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_output(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.executions.with_streaming_response.output(
+ execution_id="execution_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(ExecutionOutput, execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_output(self, async_client: AsyncDedalus) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `workspace_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.output(
+ execution_id="execution_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.workspaces.executions.with_raw_response.output(
+ execution_id="",
+ workspace_id="workspace_id",
+ )
diff --git a/tests/api_resources/workspaces/test_previews.py b/tests/api_resources/workspaces/test_previews.py
new file mode 100644
index 0000000..5d147e8
--- /dev/null
+++ b/tests/api_resources/workspaces/test_previews.py
@@ -0,0 +1,415 @@
+# 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 SyncPreviewList, AsyncPreviewList
+from dedalus_sdk.types.workspaces 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.workspaces.previews.create(
+ workspace_id="workspace_id",
+ port=0,
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Dedalus) -> None:
+ preview = client.workspaces.previews.create(
+ workspace_id="workspace_id",
+ port=0,
+ protocol="http",
+ wake_if_needed=True,
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Dedalus) -> None:
+ response = client.workspaces.previews.with_raw_response.create(
+ workspace_id="workspace_id",
+ 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.workspaces.previews.with_streaming_response.create(
+ workspace_id="workspace_id",
+ 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 `workspace_id` but received ''"):
+ client.workspaces.previews.with_raw_response.create(
+ workspace_id="",
+ port=0,
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Dedalus) -> None:
+ preview = client.workspaces.previews.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_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.workspaces.previews.with_streaming_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"):
+ client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ preview = client.workspaces.previews.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ preview = client.workspaces.previews.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.previews.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preview = response.parse()
+ assert_matches_type(SyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.previews.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ preview = response.parse()
+ assert_matches_type(SyncPreviewList[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 `workspace_id` but received ''"):
+ client.workspaces.previews.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ preview = client.workspaces.previews.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.previews.with_raw_response.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_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.workspaces.previews.with_streaming_response.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.previews.with_raw_response.delete(
+ preview_id="preview_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"):
+ client.workspaces.previews.with_raw_response.delete(
+ preview_id="",
+ workspace_id="workspace_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.workspaces.previews.create(
+ workspace_id="workspace_id",
+ 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.workspaces.previews.create(
+ workspace_id="workspace_id",
+ port=0,
+ protocol="http",
+ wake_if_needed=True,
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.previews.with_raw_response.create(
+ workspace_id="workspace_id",
+ 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.workspaces.previews.with_streaming_response.create(
+ workspace_id="workspace_id",
+ 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 `workspace_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.create(
+ workspace_id="",
+ port=0,
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
+ preview = await async_client.workspaces.previews.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_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.workspaces.previews.with_streaming_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="preview_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.retrieve(
+ preview_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ preview = await async_client.workspaces.previews.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ preview = await async_client.workspaces.previews.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.previews.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ preview = await response.parse()
+ assert_matches_type(AsyncPreviewList[Preview], preview, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.previews.with_streaming_response.list(
+ workspace_id="workspace_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(AsyncPreviewList[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 `workspace_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ preview = await async_client.workspaces.previews.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Preview, preview, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.previews.with_raw_response.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_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.workspaces.previews.with_streaming_response.delete(
+ preview_id="preview_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.delete(
+ preview_id="preview_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `preview_id` but received ''"):
+ await async_client.workspaces.previews.with_raw_response.delete(
+ preview_id="",
+ workspace_id="workspace_id",
+ )
diff --git a/tests/api_resources/workspaces/test_ssh.py b/tests/api_resources/workspaces/test_ssh.py
new file mode 100644
index 0000000..591e63a
--- /dev/null
+++ b/tests/api_resources/workspaces/test_ssh.py
@@ -0,0 +1,413 @@
+# 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 SyncSSHSessionList, AsyncSSHSessionList
+from dedalus_sdk.types.workspaces import SSHSession
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSSH:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ wake_if_needed=True,
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Dedalus) -> None:
+ response = client.workspaces.ssh.with_raw_response.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Dedalus) -> None:
+ with client.workspaces.ssh.with_streaming_response.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.create(
+ workspace_id="",
+ public_key="public_key",
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Dedalus) -> None:
+ with client.workspaces.ssh.with_streaming_response.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="session_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.ssh.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = response.parse()
+ assert_matches_type(SyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.ssh.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = response.parse()
+ assert_matches_type(SyncSSHSessionList[SSHSession], ssh, 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 `workspace_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ ssh = client.workspaces.ssh.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.ssh.with_raw_response.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: Dedalus) -> None:
+ with client.workspaces.ssh.with_streaming_response.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.delete(
+ session_id="session_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"):
+ client.workspaces.ssh.with_raw_response.delete(
+ session_id="",
+ workspace_id="workspace_id",
+ )
+
+
+class TestAsyncSSH:
+ 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:
+ ssh = await async_client.workspaces.ssh.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncDedalus) -> None:
+ ssh = await async_client.workspaces.ssh.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ wake_if_needed=True,
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.ssh.with_raw_response.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.ssh.with_streaming_response.create(
+ workspace_id="workspace_id",
+ public_key="public_key",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.create(
+ workspace_id="",
+ public_key="public_key",
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
+ ssh = await async_client.workspaces.ssh.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.ssh.with_streaming_response.retrieve(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="session_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.retrieve(
+ session_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ ssh = await async_client.workspaces.ssh.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ ssh = await async_client.workspaces.ssh.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.ssh.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = await response.parse()
+ assert_matches_type(AsyncSSHSessionList[SSHSession], ssh, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.ssh.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = await response.parse()
+ assert_matches_type(AsyncSSHSessionList[SSHSession], ssh, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ ssh = await async_client.workspaces.ssh.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.ssh.with_raw_response.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.ssh.with_streaming_response.delete(
+ session_id="session_id",
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ ssh = await response.parse()
+ assert_matches_type(SSHSession, ssh, 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 `workspace_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.delete(
+ session_id="session_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"):
+ await async_client.workspaces.ssh.with_raw_response.delete(
+ session_id="",
+ workspace_id="workspace_id",
+ )
diff --git a/tests/api_resources/workspaces/test_terminals.py b/tests/api_resources/workspaces/test_terminals.py
new file mode 100644
index 0000000..c11fb82
--- /dev/null
+++ b/tests/api_resources/workspaces/test_terminals.py
@@ -0,0 +1,429 @@
+# 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 SyncTerminalList, AsyncTerminalList
+from dedalus_sdk.types.workspaces 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.workspaces.terminals.create(
+ workspace_id="workspace_id",
+ 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.workspaces.terminals.create(
+ workspace_id="workspace_id",
+ height=0,
+ width=0,
+ cwd="cwd",
+ env={"foo": "string"},
+ shell="shell",
+ wake_if_needed=True,
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Dedalus) -> None:
+ response = client.workspaces.terminals.with_raw_response.create(
+ workspace_id="workspace_id",
+ 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.workspaces.terminals.with_streaming_response.create(
+ workspace_id="workspace_id",
+ 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 `workspace_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.create(
+ workspace_id="",
+ height=0,
+ width=0,
+ )
+
+ @parametrize
+ def test_method_retrieve(self, client: Dedalus) -> None:
+ terminal = client.workspaces.terminals.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Dedalus) -> None:
+ response = client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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.workspaces.terminals.with_streaming_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Dedalus) -> None:
+ terminal = client.workspaces.terminals.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(SyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Dedalus) -> None:
+ terminal = client.workspaces.terminals.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(SyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Dedalus) -> None:
+ response = client.workspaces.terminals.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ terminal = response.parse()
+ assert_matches_type(SyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Dedalus) -> None:
+ with client.workspaces.terminals.with_streaming_response.list(
+ workspace_id="workspace_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ terminal = response.parse()
+ assert_matches_type(SyncTerminalList[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 `workspace_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ def test_method_delete(self, client: Dedalus) -> None:
+ terminal = client.workspaces.terminals.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: Dedalus) -> None:
+ response = client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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.workspaces.terminals.with_streaming_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"):
+ client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="",
+ workspace_id="workspace_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.workspaces.terminals.create(
+ workspace_id="workspace_id",
+ 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.workspaces.terminals.create(
+ workspace_id="workspace_id",
+ height=0,
+ width=0,
+ cwd="cwd",
+ env={"foo": "string"},
+ shell="shell",
+ wake_if_needed=True,
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.terminals.with_raw_response.create(
+ workspace_id="workspace_id",
+ 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.workspaces.terminals.with_streaming_response.create(
+ workspace_id="workspace_id",
+ 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 `workspace_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.create(
+ workspace_id="",
+ height=0,
+ width=0,
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncDedalus) -> None:
+ terminal = await async_client.workspaces.terminals.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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.workspaces.terminals.with_streaming_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="terminal_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.retrieve(
+ terminal_id="",
+ workspace_id="workspace_id",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncDedalus) -> None:
+ terminal = await async_client.workspaces.terminals.list(
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(AsyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncDedalus) -> None:
+ terminal = await async_client.workspaces.terminals.list(
+ workspace_id="workspace_id",
+ cursor="cursor",
+ limit=0,
+ )
+ assert_matches_type(AsyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.terminals.with_raw_response.list(
+ workspace_id="workspace_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ terminal = await response.parse()
+ assert_matches_type(AsyncTerminalList[Terminal], terminal, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncDedalus) -> None:
+ async with async_client.workspaces.terminals.with_streaming_response.list(
+ workspace_id="workspace_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(AsyncTerminalList[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 `workspace_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.list(
+ workspace_id="",
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncDedalus) -> None:
+ terminal = await async_client.workspaces.terminals.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_id",
+ )
+ assert_matches_type(Terminal, terminal, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncDedalus) -> None:
+ response = await async_client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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.workspaces.terminals.with_streaming_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="workspace_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 `workspace_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="terminal_id",
+ workspace_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `terminal_id` but received ''"):
+ await async_client.workspaces.terminals.with_raw_response.delete(
+ terminal_id="",
+ workspace_id="workspace_id",
+ )
diff --git a/tests/conftest.py b/tests/conftest.py
index d4a1931..db34904 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -10,15 +10,15 @@
import pytest
from pytest_asyncio import is_async_test
-from dedalus import Dedalus, AsyncDedalus, DefaultAioHttpClient
-from dedalus._utils import is_dict
+from dedalus_sdk import Dedalus, AsyncDedalus, DefaultAioHttpClient
+from dedalus_sdk._utils import is_dict
if TYPE_CHECKING:
from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage]
pytest.register_assert_rewrite("tests.utils")
-logging.getLogger("dedalus").setLevel(logging.DEBUG)
+logging.getLogger("dedalus_sdk").setLevel(logging.DEBUG)
# automatically add `pytest.mark.asyncio()` to all of our async tests
diff --git a/tests/test_client.py b/tests/test_client.py
index 4af7141..e15d38e 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -19,12 +19,12 @@
from respx import MockRouter
from pydantic import ValidationError
-from dedalus import Dedalus, AsyncDedalus, APIResponseValidationError
-from dedalus._types import Omit
-from dedalus._utils import asyncify
-from dedalus._models import BaseModel, FinalRequestOptions
-from dedalus._exceptions import DedalusError, APIStatusError, APITimeoutError, APIResponseValidationError
-from dedalus._base_client import (
+from dedalus_sdk import Dedalus, AsyncDedalus, APIResponseValidationError
+from dedalus_sdk._types import Omit
+from dedalus_sdk._utils import asyncify
+from dedalus_sdk._models import BaseModel, FinalRequestOptions
+from dedalus_sdk._exceptions import APIStatusError, APITimeoutError, APIResponseValidationError
+from dedalus_sdk._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
BaseClient,
@@ -286,10 +286,10 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic
# to_raw_response_wrapper leaks through the @functools.wraps() decorator.
#
# removing the decorator fixes the leak for reasons we don't understand.
- "dedalus/_legacy_response.py",
- "dedalus/_response.py",
+ "dedalus_sdk/_legacy_response.py",
+ "dedalus_sdk/_response.py",
# pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason.
- "dedalus/_compat.py",
+ "dedalus_sdk/_compat.py",
# Standard library leaks we don't care about.
"/logging/__init__.py",
]
@@ -400,12 +400,21 @@ def test_default_headers_option(self) -> None:
def test_validate_headers(self) -> None:
client = Dedalus(base_url=base_url, api_key=api_key, _strict_response_validation=True)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- assert request.headers.get("api_key") == api_key
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
- with pytest.raises(DedalusError):
- with update_env(**{"PETSTORE_API_KEY": Omit()}):
- client2 = Dedalus(base_url=base_url, api_key=None, _strict_response_validation=True)
- _ = client2
+ with update_env(**{"DEDALUS_API_KEY": Omit()}):
+ client2 = Dedalus(base_url=base_url, api_key=None, _strict_response_validation=True)
+
+ with pytest.raises(
+ TypeError,
+ match="Could not resolve authentication method. Expected either x_api_key or api_key to be set. Or for one of the `x-api-key` or `Authorization` headers to be explicitly omitted",
+ ):
+ client2._build_request(FinalRequestOptions(method="get", url="/foo"))
+
+ request2 = client2._build_request(
+ FinalRequestOptions(method="get", url="/foo", headers={"Authorization": Omit()})
+ )
+ assert request2.headers.get("Authorization") is None
def test_default_query_option(self) -> None:
client = Dedalus(
@@ -674,6 +683,37 @@ class Model(BaseModel):
assert isinstance(response, Model)
assert response.foo == 2
+ @pytest.mark.respx(base_url=base_url)
+ def test_idempotency_header_options(self, respx_mock: MockRouter, client: Dedalus) -> None:
+ respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={}))
+
+ response = client.post("/foo", cast_to=httpx.Response)
+
+ header = response.request.headers.get("Idempotency-Key")
+ assert header is not None
+ assert header.startswith("stainless-python-retry")
+
+ # explicit header
+ response = client.post(
+ "/foo",
+ cast_to=httpx.Response,
+ options=make_request_options(extra_headers={"Idempotency-Key": "custom-key"}),
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
+ response = client.post(
+ "/foo",
+ cast_to=httpx.Response,
+ options=make_request_options(extra_headers={"idempotency-key": "custom-key"}),
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
+ # custom argument
+ response = client.post(
+ "/foo", cast_to=httpx.Response, options=make_request_options(idempotency_key="custom-key")
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
def test_base_url_setter(self) -> None:
client = Dedalus(base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True)
assert client.base_url == "https://example.com/from_init/"
@@ -846,27 +886,27 @@ def test_parse_retry_after_header(
calculated = client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Dedalus) -> None:
- respx_mock.get("/store/inventory").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v1/workspaces").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- client.store.with_streaming_response.list_inventory().__enter__()
+ client.workspaces.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__enter__()
assert _get_open_connections(client) == 0
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Dedalus) -> None:
- respx_mock.get("/store/inventory").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v1/workspaces").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- client.store.with_streaming_response.list_inventory().__enter__()
+ client.workspaces.with_streaming_response.create(memory_mib=0, storage_gib=0, vcpu=0).__enter__()
assert _get_open_connections(client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
@pytest.mark.parametrize("failure_mode", ["status", "exception"])
def test_retries_taken(
@@ -889,15 +929,15 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = client.store.with_raw_response.list_inventory()
+ response = client.workspaces.with_raw_response.create(memory_mib=0, storage_gib=0, vcpu=0)
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_omit_retry_count_header(
self, client: Dedalus, failures_before_success: int, respx_mock: MockRouter
@@ -913,14 +953,16 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = client.store.with_raw_response.list_inventory(extra_headers={"x-stainless-retry-count": Omit()})
+ response = client.workspaces.with_raw_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": Omit()}
+ )
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
def test_overwrite_retry_count_header(
self, client: Dedalus, failures_before_success: int, respx_mock: MockRouter
@@ -936,9 +978,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = client.store.with_raw_response.list_inventory(extra_headers={"x-stainless-retry-count": "42"})
+ response = client.workspaces.with_raw_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": "42"}
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
@@ -1173,10 +1217,10 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic
# to_raw_response_wrapper leaks through the @functools.wraps() decorator.
#
# removing the decorator fixes the leak for reasons we don't understand.
- "dedalus/_legacy_response.py",
- "dedalus/_response.py",
+ "dedalus_sdk/_legacy_response.py",
+ "dedalus_sdk/_response.py",
# pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason.
- "dedalus/_compat.py",
+ "dedalus_sdk/_compat.py",
# Standard library leaks we don't care about.
"/logging/__init__.py",
]
@@ -1291,12 +1335,21 @@ async def test_default_headers_option(self) -> None:
def test_validate_headers(self) -> None:
client = AsyncDedalus(base_url=base_url, api_key=api_key, _strict_response_validation=True)
request = client._build_request(FinalRequestOptions(method="get", url="/foo"))
- assert request.headers.get("api_key") == api_key
+ assert request.headers.get("Authorization") == f"Bearer {api_key}"
- with pytest.raises(DedalusError):
- with update_env(**{"PETSTORE_API_KEY": Omit()}):
- client2 = AsyncDedalus(base_url=base_url, api_key=None, _strict_response_validation=True)
- _ = client2
+ with update_env(**{"DEDALUS_API_KEY": Omit()}):
+ client2 = AsyncDedalus(base_url=base_url, api_key=None, _strict_response_validation=True)
+
+ with pytest.raises(
+ TypeError,
+ match="Could not resolve authentication method. Expected either x_api_key or api_key to be set. Or for one of the `x-api-key` or `Authorization` headers to be explicitly omitted",
+ ):
+ client2._build_request(FinalRequestOptions(method="get", url="/foo"))
+
+ request2 = client2._build_request(
+ FinalRequestOptions(method="get", url="/foo", headers={"Authorization": Omit()})
+ )
+ assert request2.headers.get("Authorization") is None
async def test_default_query_option(self) -> None:
client = AsyncDedalus(
@@ -1569,6 +1622,37 @@ class Model(BaseModel):
assert isinstance(response, Model)
assert response.foo == 2
+ @pytest.mark.respx(base_url=base_url)
+ async def test_idempotency_header_options(self, respx_mock: MockRouter, async_client: AsyncDedalus) -> None:
+ respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={}))
+
+ response = await async_client.post("/foo", cast_to=httpx.Response)
+
+ header = response.request.headers.get("Idempotency-Key")
+ assert header is not None
+ assert header.startswith("stainless-python-retry")
+
+ # explicit header
+ response = await async_client.post(
+ "/foo",
+ cast_to=httpx.Response,
+ options=make_request_options(extra_headers={"Idempotency-Key": "custom-key"}),
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
+ response = await async_client.post(
+ "/foo",
+ cast_to=httpx.Response,
+ options=make_request_options(extra_headers={"idempotency-key": "custom-key"}),
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
+ # custom argument
+ response = await async_client.post(
+ "/foo", cast_to=httpx.Response, options=make_request_options(idempotency_key="custom-key")
+ )
+ assert response.request.headers.get("Idempotency-Key") == "custom-key"
+
async def test_base_url_setter(self) -> None:
client = AsyncDedalus(
base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True
@@ -1752,29 +1836,33 @@ async def test_parse_retry_after_header(
calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers)
assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType]
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_timeout_errors_doesnt_leak(
self, respx_mock: MockRouter, async_client: AsyncDedalus
) -> None:
- respx_mock.get("/store/inventory").mock(side_effect=httpx.TimeoutException("Test timeout error"))
+ respx_mock.post("/v1/workspaces").mock(side_effect=httpx.TimeoutException("Test timeout error"))
with pytest.raises(APITimeoutError):
- await async_client.store.with_streaming_response.list_inventory().__aenter__()
+ await async_client.workspaces.with_streaming_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0
+ ).__aenter__()
assert _get_open_connections(async_client) == 0
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, async_client: AsyncDedalus) -> None:
- respx_mock.get("/store/inventory").mock(return_value=httpx.Response(500))
+ respx_mock.post("/v1/workspaces").mock(return_value=httpx.Response(500))
with pytest.raises(APIStatusError):
- await async_client.store.with_streaming_response.list_inventory().__aenter__()
+ await async_client.workspaces.with_streaming_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0
+ ).__aenter__()
assert _get_open_connections(async_client) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
@pytest.mark.parametrize("failure_mode", ["status", "exception"])
async def test_retries_taken(
@@ -1797,15 +1885,15 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = await client.store.with_raw_response.list_inventory()
+ response = await client.workspaces.with_raw_response.create(memory_mib=0, storage_gib=0, vcpu=0)
assert response.retries_taken == failures_before_success
assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_omit_retry_count_header(
self, async_client: AsyncDedalus, failures_before_success: int, respx_mock: MockRouter
@@ -1821,16 +1909,16 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = await client.store.with_raw_response.list_inventory(
- extra_headers={"x-stainless-retry-count": Omit()}
+ response = await client.workspaces.with_raw_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": Omit()}
)
assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
- @mock.patch("dedalus._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
+ @mock.patch("dedalus_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
async def test_overwrite_retry_count_header(
self, async_client: AsyncDedalus, failures_before_success: int, respx_mock: MockRouter
@@ -1846,9 +1934,11 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
return httpx.Response(500)
return httpx.Response(200)
- respx_mock.get("/store/inventory").mock(side_effect=retry_handler)
+ respx_mock.post("/v1/workspaces").mock(side_effect=retry_handler)
- response = await client.store.with_raw_response.list_inventory(extra_headers={"x-stainless-retry-count": "42"})
+ response = await client.workspaces.with_raw_response.create(
+ memory_mib=0, storage_gib=0, vcpu=0, extra_headers={"x-stainless-retry-count": "42"}
+ )
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py
index 78be891..e733530 100644
--- a/tests/test_deepcopy.py
+++ b/tests/test_deepcopy.py
@@ -1,4 +1,4 @@
-from dedalus._utils import deepcopy_minimal
+from dedalus_sdk._utils import deepcopy_minimal
def assert_different_identities(obj1: object, obj2: object) -> None:
diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py
index 1382470..86bfebd 100644
--- a/tests/test_extract_files.py
+++ b/tests/test_extract_files.py
@@ -4,8 +4,8 @@
import pytest
-from dedalus._types import FileTypes
-from dedalus._utils import extract_files
+from dedalus_sdk._types import FileTypes
+from dedalus_sdk._utils import extract_files
def test_removes_files_from_input() -> None:
diff --git a/tests/test_files.py b/tests/test_files.py
index 1a51d8f..deb1fc4 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -4,7 +4,7 @@
import pytest
from dirty_equals import IsDict, IsList, IsBytes, IsTuple
-from dedalus._files import to_httpx_files, async_to_httpx_files
+from dedalus_sdk._files import to_httpx_files, async_to_httpx_files
readme_path = Path(__file__).parent.parent.joinpath("README.md")
diff --git a/tests/test_models.py b/tests/test_models.py
index 08758bf..58a18a1 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -7,9 +7,9 @@
import pydantic
from pydantic import Field
-from dedalus._utils import PropertyInfo
-from dedalus._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
-from dedalus._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
+from dedalus_sdk._utils import PropertyInfo
+from dedalus_sdk._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
+from dedalus_sdk._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
class BasicModel(BaseModel):
diff --git a/tests/test_qs.py b/tests/test_qs.py
index 017b5d7..3ca928c 100644
--- a/tests/test_qs.py
+++ b/tests/test_qs.py
@@ -4,7 +4,7 @@
import pytest
-from dedalus._qs import Querystring, stringify
+from dedalus_sdk._qs import Querystring, stringify
def test_empty() -> None:
diff --git a/tests/test_required_args.py b/tests/test_required_args.py
index a3b7c4b..d8a3f53 100644
--- a/tests/test_required_args.py
+++ b/tests/test_required_args.py
@@ -2,7 +2,7 @@
import pytest
-from dedalus._utils import required_args
+from dedalus_sdk._utils import required_args
def test_too_many_positional_params() -> None:
diff --git a/tests/test_response.py b/tests/test_response.py
index 84f6d3c..790d212 100644
--- a/tests/test_response.py
+++ b/tests/test_response.py
@@ -6,8 +6,8 @@
import pytest
import pydantic
-from dedalus import Dedalus, BaseModel, AsyncDedalus
-from dedalus._response import (
+from dedalus_sdk import Dedalus, BaseModel, AsyncDedalus
+from dedalus_sdk._response import (
APIResponse,
BaseAPIResponse,
AsyncAPIResponse,
@@ -15,8 +15,8 @@
AsyncBinaryAPIResponse,
extract_response_type,
)
-from dedalus._streaming import Stream
-from dedalus._base_client import FinalRequestOptions
+from dedalus_sdk._streaming import Stream
+from dedalus_sdk._base_client import FinalRequestOptions
class ConcreteBaseAPIResponse(APIResponse[bytes]): ...
@@ -37,7 +37,7 @@ def test_extract_response_type_direct_classes() -> None:
def test_extract_response_type_direct_class_missing_type_arg() -> None:
with pytest.raises(
RuntimeError,
- match="Expected type to have a type argument at index 0 but it did not",
+ match="Expected type to have a type argument at index 0 but it did not",
):
extract_response_type(AsyncAPIResponse)
@@ -68,7 +68,7 @@ def test_response_parse_mismatched_basemodel(client: Dedalus) -> None:
with pytest.raises(
TypeError,
- match="Pydantic models must subclass our base model type, e.g. `from dedalus import BaseModel`",
+ match="Pydantic models must subclass our base model type, e.g. `from dedalus_sdk import BaseModel`",
):
response.parse(to=PydanticModel)
@@ -86,7 +86,7 @@ async def test_async_response_parse_mismatched_basemodel(async_client: AsyncDeda
with pytest.raises(
TypeError,
- match="Pydantic models must subclass our base model type, e.g. `from dedalus import BaseModel`",
+ match="Pydantic models must subclass our base model type, e.g. `from dedalus_sdk import BaseModel`",
):
await response.parse(to=PydanticModel)
diff --git a/tests/test_streaming.py b/tests/test_streaming.py
index b3b2c99..4b29f43 100644
--- a/tests/test_streaming.py
+++ b/tests/test_streaming.py
@@ -5,8 +5,8 @@
import httpx
import pytest
-from dedalus import Dedalus, AsyncDedalus
-from dedalus._streaming import Stream, AsyncStream, ServerSentEvent
+from dedalus_sdk import Dedalus, AsyncDedalus
+from dedalus_sdk._streaming import Stream, AsyncStream, ServerSentEvent
@pytest.mark.asyncio
diff --git a/tests/test_transform.py b/tests/test_transform.py
index 1b5bd24..dee2af7 100644
--- a/tests/test_transform.py
+++ b/tests/test_transform.py
@@ -8,15 +8,15 @@
import pytest
-from dedalus._types import Base64FileInput, omit, not_given
-from dedalus._utils import (
+from dedalus_sdk._types import Base64FileInput, omit, not_given
+from dedalus_sdk._utils import (
PropertyInfo,
transform as _transform,
parse_datetime,
async_transform as _async_transform,
)
-from dedalus._compat import PYDANTIC_V1
-from dedalus._models import BaseModel
+from dedalus_sdk._compat import PYDANTIC_V1
+from dedalus_sdk._models import BaseModel
_T = TypeVar("_T")
diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py
index 2b3778d..e129974 100644
--- a/tests/test_utils/test_datetime_parse.py
+++ b/tests/test_utils/test_datetime_parse.py
@@ -8,7 +8,7 @@
import pytest
-from dedalus._utils import parse_date, parse_datetime
+from dedalus_sdk._utils import parse_date, parse_datetime
def create_tz(minutes: int) -> timezone:
diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py
index 60f952c..246547d 100644
--- a/tests/test_utils/test_json.py
+++ b/tests/test_utils/test_json.py
@@ -5,8 +5,8 @@
import pydantic
-from dedalus import _compat
-from dedalus._utils._json import openapi_dumps
+from dedalus_sdk import _compat
+from dedalus_sdk._utils._json import openapi_dumps
class TestOpenapiDumps:
diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py
index f4ba3a8..935fd89 100644
--- a/tests/test_utils/test_proxy.py
+++ b/tests/test_utils/test_proxy.py
@@ -2,7 +2,7 @@
from typing import Any
from typing_extensions import override
-from dedalus._utils import LazyProxy
+from dedalus_sdk._utils import LazyProxy
class RecursiveLazyProxy(LazyProxy[Any]):
diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py
index cc65b3d..ef8c14e 100644
--- a/tests/test_utils/test_typing.py
+++ b/tests/test_utils/test_typing.py
@@ -2,7 +2,7 @@
from typing import Generic, TypeVar, cast
-from dedalus._utils import extract_type_var_from_base
+from dedalus_sdk._utils import extract_type_var_from_base
_T = TypeVar("_T")
_T2 = TypeVar("_T2")
diff --git a/tests/utils.py b/tests/utils.py
index 0036b7e..09df165 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -8,8 +8,8 @@
from datetime import date, datetime
from typing_extensions import Literal, get_args, get_origin, assert_type
-from dedalus._types import Omit, NoneType
-from dedalus._utils import (
+from dedalus_sdk._types import Omit, NoneType
+from dedalus_sdk._utils import (
is_dict,
is_list,
is_list_type,
@@ -19,8 +19,8 @@
is_annotated_type,
is_type_alias_type,
)
-from dedalus._compat import PYDANTIC_V1, field_outer_type, get_model_fields
-from dedalus._models import BaseModel
+from dedalus_sdk._compat import PYDANTIC_V1, field_outer_type, get_model_fields
+from dedalus_sdk._models import BaseModel
BaseModelT = TypeVar("BaseModelT", bound=BaseModel)
diff --git a/uv.lock b/uv.lock
index 745d6ea..91129d1 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,17 +2,17 @@ version = 1
revision = 3
requires-python = ">=3.9"
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version < '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version < '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version < '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version < '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version < '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version < '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
conflicts = [[
- { package = "dedalus", group = "pydantic-v1" },
- { package = "dedalus", group = "pydantic-v2" },
+ { package = "dedalus-sdk", group = "pydantic-v1" },
+ { package = "dedalus-sdk", group = "pydantic-v2" },
]]
[[package]]
@@ -31,7 +31,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohappyeyeballs" },
{ name = "aiosignal" },
- { name = "async-timeout", marker = "python_full_version < '3.11' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "async-timeout", marker = "python_full_version < '3.11' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
{ name = "attrs" },
{ name = "frozenlist" },
{ name = "multidict" },
@@ -167,7 +167,7 @@ version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "frozenlist" },
- { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
wheels = [
@@ -188,9 +188,9 @@ name = "anyio"
version = "4.12.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "exceptiongroup", marker = "python_full_version < '3.11' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.11' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
{ name = "idna" },
- { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
wheels = [
@@ -243,15 +243,15 @@ wheels = [
]
[[package]]
-name = "dedalus"
+name = "dedalus-sdk"
version = "0.0.1"
source = { editable = "." }
dependencies = [
{ name = "anyio" },
{ name = "distro" },
{ name = "httpx" },
- { name = "pydantic", version = "1.10.26", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-7-dedalus-pydantic-v1'" },
- { name = "pydantic", version = "2.12.5", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
+ { name = "pydantic", version = "1.10.26", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-11-dedalus-sdk-pydantic-v1'" },
+ { name = "pydantic", version = "2.12.5", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
{ name = "sniffio" },
{ name = "typing-extensions" },
]
@@ -261,6 +261,9 @@ aiohttp = [
{ name = "aiohttp" },
{ name = "httpx-aiohttp" },
]
+websockets = [
+ { name = "websockets" },
+]
[package.dev-dependencies]
dev = [
@@ -268,16 +271,16 @@ dev = [
{ name = "importlib-metadata" },
{ name = "mypy" },
{ name = "pyright" },
- { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest-asyncio", version = "1.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest-asyncio", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
{ name = "pytest-xdist" },
{ name = "respx" },
{ name = "rich" },
{ name = "ruff" },
- { name = "time-machine", version = "2.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "time-machine", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "time-machine", version = "2.19.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "time-machine", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
pydantic-v1 = [
{ name = "pydantic", version = "1.10.26", source = { registry = "https://pypi.org/simple" } },
@@ -295,9 +298,10 @@ requires-dist = [
{ name = "httpx-aiohttp", marker = "extra == 'aiohttp'", specifier = ">=0.1.9" },
{ name = "pydantic", specifier = ">=1.9.0,<3" },
{ name = "sniffio" },
- { name = "typing-extensions", specifier = ">=4.10,<5" },
+ { name = "typing-extensions", specifier = ">=4.14,<5" },
+ { name = "websockets", marker = "extra == 'websockets'", specifier = ">=13,<16" },
]
-provides-extras = ["aiohttp"]
+provides-extras = ["aiohttp", "websockets"]
[package.metadata.requires-dev]
dev = [
@@ -342,7 +346,7 @@ name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
@@ -583,10 +587,10 @@ name = "iniconfig"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
wheels = [
@@ -601,7 +605,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "mdurl", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "mdurl", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
wheels = [
@@ -613,13 +617,13 @@ name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
dependencies = [
- { name = "mdurl", marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "mdurl", marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
@@ -640,7 +644,7 @@ name = "multidict"
version = "6.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "typing-extensions", marker = "python_full_version < '3.11' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" }
wheels = [
@@ -798,7 +802,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "pathspec" },
- { name = "tomli", marker = "python_full_version < '3.11' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "tomli", marker = "python_full_version < '3.11' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1e/e3/034322d5a779685218ed69286c32faa505247f1f096251ef66c8fd203b08/mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03", size = 3352114, upload-time = "2025-07-14T20:34:30.181Z" }
@@ -1019,7 +1023,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "typing-extensions", marker = "extra == 'group-7-dedalus-pydantic-v1'" },
+ { name = "typing-extensions", marker = "extra == 'group-11-dedalus-sdk-pydantic-v1'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7b/da/fd89f987a376c807cd81ea0eff4589aade783bbb702637b4734ef2c743a2/pydantic-1.10.26.tar.gz", hash = "sha256:8c6aa39b494c5af092e690127c283d84f363ac36017106a9e66cb33a22ac412e", size = 357906, upload-time = "2025-12-18T15:47:46.557Z" }
wheels = [
@@ -1061,17 +1065,17 @@ name = "pydantic"
version = "2.12.5"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version < '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version < '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version < '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version < '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
dependencies = [
- { name = "annotated-types", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
- { name = "pydantic-core", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
- { name = "typing-extensions", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
- { name = "typing-inspection", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
+ { name = "annotated-types", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
+ { name = "pydantic-core", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
+ { name = "typing-extensions", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
+ { name = "typing-inspection", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" }
wheels = [
@@ -1083,7 +1087,7 @@ name = "pydantic-core"
version = "2.41.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
+ { name = "typing-extensions", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" }
wheels = [
@@ -1239,13 +1243,13 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "exceptiongroup", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "packaging", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pluggy", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pygments", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "tomli", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "colorama", marker = "(python_full_version < '3.10' and sys_platform == 'win32') or (python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "packaging", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pluggy", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pygments", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "tomli", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
wheels = [
@@ -1257,19 +1261,19 @@ name = "pytest"
version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
dependencies = [
- { name = "colorama", marker = "(python_full_version >= '3.10' and sys_platform == 'win32') or (python_full_version < '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "exceptiongroup", marker = "python_full_version == '3.10.*' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "packaging", marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pluggy", marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pygments", marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "tomli", marker = "python_full_version == '3.10.*' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "colorama", marker = "(python_full_version >= '3.10' and sys_platform == 'win32') or (python_full_version < '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2') or (sys_platform != 'win32' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "exceptiongroup", marker = "python_full_version == '3.10.*' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "packaging", marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pluggy", marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pygments", marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "tomli", marker = "python_full_version == '3.10.*' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
wheels = [
@@ -1284,9 +1288,9 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "backports-asyncio-runner", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "typing-extensions", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "backports-asyncio-runner", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "typing-extensions", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/86/9e3c5f48f7b7b638b216e4b9e645f54d199d7abbbab7a64a13b4e12ba10f/pytest_asyncio-1.2.0.tar.gz", hash = "sha256:c609a64a2a8768462d0c99811ddb8bd2583c33fd33cf7f21af1c142e824ffb57", size = 50119, upload-time = "2025-09-12T07:33:53.816Z" }
wheels = [
@@ -1298,15 +1302,15 @@ name = "pytest-asyncio"
version = "1.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
dependencies = [
- { name = "backports-asyncio-runner", marker = "python_full_version == '3.10.*' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "typing-extensions", marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version < '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2') or (python_full_version >= '3.13' and extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "backports-asyncio-runner", marker = "python_full_version == '3.10.*' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "typing-extensions", marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version < '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2') or (python_full_version >= '3.13' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
wheels = [
@@ -1319,8 +1323,8 @@ version = "3.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "execnet" },
- { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "pytest", version = "9.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
wheels = [
@@ -1332,7 +1336,7 @@ name = "python-dateutil"
version = "2.9.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "six", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "six", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
wheels = [
@@ -1356,8 +1360,8 @@ name = "rich"
version = "14.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
- { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
+ { name = "markdown-it-py", version = "4.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" }
@@ -1417,7 +1421,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "python-dateutil", marker = "python_full_version < '3.10' or (extra == 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2')" },
+ { name = "python-dateutil", marker = "python_full_version < '3.10' or (extra == 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f8/a4/1b5fdd165f61b67f445fac2a7feb0c655118edef429cd09ff5a8067f7f1d/time_machine-2.19.0.tar.gz", hash = "sha256:7c5065a8b3f2bbb449422c66ef71d114d3f909c276a6469642ecfffb6a0fcd29", size = 14576, upload-time = "2025-08-19T17:22:08.402Z" }
wheels = [
@@ -1516,10 +1520,10 @@ name = "time-machine"
version = "3.2.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
- "python_full_version >= '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-7-dedalus-pydantic-v1' and extra == 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra == 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
- "python_full_version >= '3.10' and extra != 'group-7-dedalus-pydantic-v1' and extra != 'group-7-dedalus-pydantic-v2'",
+ "python_full_version >= '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra == 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra == 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
+ "python_full_version >= '3.10' and extra != 'group-11-dedalus-sdk-pydantic-v1' and extra != 'group-11-dedalus-sdk-pydantic-v2'",
]
sdist = { url = "https://files.pythonhosted.org/packages/02/fc/37b02f6094dbb1f851145330460532176ed2f1dc70511a35828166c41e52/time_machine-3.2.0.tar.gz", hash = "sha256:a4ddd1cea17b8950e462d1805a42b20c81eb9aafc8f66b392dd5ce997e037d79", size = 14804, upload-time = "2025-12-17T23:33:02.599Z" }
wheels = [
@@ -1670,13 +1674,89 @@ name = "typing-inspection"
version = "0.4.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "extra == 'group-7-dedalus-pydantic-v2' or extra != 'group-7-dedalus-pydantic-v1'" },
+ { name = "typing-extensions", marker = "extra == 'group-11-dedalus-sdk-pydantic-v2' or extra != 'group-11-dedalus-sdk-pydantic-v1'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
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"