From f9cd760421fd8d06c920e23c12e9c289dab2d81a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 23:11:43 +0000 Subject: [PATCH 1/7] chore: update SDK settings --- .github/workflows/publish-pypi.yml | 28 ++++++++++++ .github/workflows/release-doctor.yml | 21 +++++++++ .release-please-manifest.json | 3 ++ .stats.yml | 2 +- CONTRIBUTING.md | 4 +- README.md | 14 +++--- bin/check-release-environment | 21 +++++++++ pyproject.toml | 6 +-- release-please-config.json | 66 +++++++++++++++++++++++++++ src/dedalus/_version.py | 2 +- src/dedalus/resources/pets.py | 8 ++-- src/dedalus/resources/store/orders.py | 8 ++-- src/dedalus/resources/store/store.py | 8 ++-- src/dedalus/resources/users.py | 8 ++-- 14 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 .github/workflows/publish-pypi.yml create mode 100644 .github/workflows/release-doctor.yml create mode 100644 .release-please-manifest.json create mode 100644 bin/check-release-environment create mode 100644 release-please-config.json diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..aeccf42 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,28 @@ +# 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 + + 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 + env: + PYPI_TOKEN: ${{ secrets.DEDALUS_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..207944f --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,21 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + 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 + env: + PYPI_TOKEN: ${{ secrets.DEDALUS_PYPI_TOKEN || secrets.PYPI_TOKEN }} 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..aa1e1ca 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 +config_hash: b5ae07326ce7a3b291ef8123aaed8b9f diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c4eeefc..e1eda1e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: @@ -113,7 +113,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/README.md b/README.md index 2933a7f..7a5f9db 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ 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 the production repo +pip install git+ssh://git@github.com/dedalus-labs/dedalus-python.git ``` > [!NOTE] @@ -92,8 +92,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 the production repo +pip install 'dedalus[aiohttp] @ git+ssh://git@github.com/dedalus-labs/dedalus-python.git' ``` Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: @@ -277,9 +277,9 @@ store = response.parse() # get the object that `store.list_inventory()` would h print(store) ``` -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/_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/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. #### `.with_streaming_response` @@ -383,7 +383,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 diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..b845b0f --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${PYPI_TOKEN}" ]; then + errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") +fi + +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/pyproject.toml b/pyproject.toml index a7e6544..c0a0549 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,8 +37,8 @@ classifiers = [ ] [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"] @@ -112,7 +112,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"] diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..16d61c9 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,66 @@ +{ + "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 + } + ], + "release-type": "python", + "extra-files": [ + "src/dedalus/_version.py" + ] +} \ No newline at end of file diff --git a/src/dedalus/_version.py b/src/dedalus/_version.py index 453627e..08dd84a 100644 --- a/src/dedalus/_version.py +++ b/src/dedalus/_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" +__version__ = "0.0.1" # x-release-please-version diff --git a/src/dedalus/resources/pets.py b/src/dedalus/resources/pets.py index 583b7f4..8978816 100644 --- a/src/dedalus/resources/pets.py +++ b/src/dedalus/resources/pets.py @@ -59,7 +59,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers """ return PetsResourceWithRawResponse(self) @@ -68,7 +68,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response """ return PetsResourceWithStreamingResponse(self) @@ -410,7 +410,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers """ return AsyncPetsResourceWithRawResponse(self) @@ -419,7 +419,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response """ return AsyncPetsResourceWithStreamingResponse(self) diff --git a/src/dedalus/resources/store/orders.py b/src/dedalus/resources/store/orders.py index 3b8381f..b0163fe 100644 --- a/src/dedalus/resources/store/orders.py +++ b/src/dedalus/resources/store/orders.py @@ -34,7 +34,7 @@ def with_raw_response(self) -> OrdersResourceWithRawResponse: 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) @@ -43,7 +43,7 @@ def with_streaming_response(self) -> OrdersResourceWithStreamingResponse: """ 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) @@ -173,7 +173,7 @@ def with_raw_response(self) -> AsyncOrdersResourceWithRawResponse: 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) @@ -182,7 +182,7 @@ def with_streaming_response(self) -> AsyncOrdersResourceWithStreamingResponse: """ 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) diff --git a/src/dedalus/resources/store/store.py b/src/dedalus/resources/store/store.py index 1d0940c..60212c3 100644 --- a/src/dedalus/resources/store/store.py +++ b/src/dedalus/resources/store/store.py @@ -41,7 +41,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers """ return StoreResourceWithRawResponse(self) @@ -50,7 +50,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response """ return StoreResourceWithStreamingResponse(self) @@ -88,7 +88,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#accessing-raw-response-data-eg-headers """ return AsyncStoreResourceWithRawResponse(self) @@ -97,7 +97,7 @@ 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 + For more information, see https://www.github.com/dedalus-labs/dedalus-python#with_streaming_response """ return AsyncStoreResourceWithStreamingResponse(self) diff --git a/src/dedalus/resources/users.py b/src/dedalus/resources/users.py index 306ec10..a367e1b 100644 --- a/src/dedalus/resources/users.py +++ b/src/dedalus/resources/users.py @@ -33,7 +33,7 @@ def with_raw_response(self) -> UsersResourceWithRawResponse: 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) @@ -42,7 +42,7 @@ def with_streaming_response(self) -> UsersResourceWithStreamingResponse: """ 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) @@ -331,7 +331,7 @@ def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: 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) @@ -340,7 +340,7 @@ def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: """ 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) From 958004593a4a1369dd7983af2591ac5e0ca655af Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 23:12:41 +0000 Subject: [PATCH 2/7] chore: update SDK settings --- .stats.yml | 2 +- README.md | 13 ++-- pyproject.toml | 2 +- requirements-dev.lock | 12 +-- uv.lock | 170 +++++++++++++++++++++--------------------- 5 files changed, 98 insertions(+), 101 deletions(-) diff --git a/.stats.yml b/.stats.yml index aa1e1ca..5e94783 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: b5ae07326ce7a3b291ef8123aaed8b9f +config_hash: e91c30e20561e6271d4069e7f1576f1f diff --git a/README.md b/README.md index 7a5f9db..951ff5a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Dedalus Python API library -[![PyPI version](https://img.shields.io/pypi/v/dedalus.svg?label=pypi%20(stable))](https://pypi.org/project/dedalus/) +[![PyPI version](https://img.shields.io/pypi/v/dedalus-sdk.svg?label=pypi%20(stable))](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, @@ -25,13 +25,10 @@ The full API of this library can be found in [api.md](api.md). ## Installation ```sh -# install from the production repo -pip install git+ssh://git@github.com/dedalus-labs/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). @@ -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 the production repo -pip install 'dedalus[aiohttp] @ git+ssh://git@github.com/dedalus-labs/dedalus-python.git' +# install from PyPI +pip install dedalus-sdk[aiohttp] ``` Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: diff --git a/pyproject.toml b/pyproject.toml index c0a0549..791f2b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "dedalus" +name = "dedalus-sdk" version = "0.0.1" description = "The official Python library for the dedalus API" dynamic = ["readme"] 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/uv.lock b/uv.lock index 745d6ea..1f5aaf7 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" }, ] @@ -268,16 +268,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" } }, @@ -342,7 +342,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 +583,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 +601,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 +613,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 +640,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 +798,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 +1019,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 +1061,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 +1083,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 +1239,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 +1257,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 +1284,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 +1298,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 +1319,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 +1332,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 +1356,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 +1417,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 +1516,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,7 +1670,7 @@ 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 = [ From 22408628cfde349577c7830b4fb2326e91f43444 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 23:12:54 +0000 Subject: [PATCH 3/7] chore: update SDK settings --- .github/workflows/publish-pypi.yml | 5 +++-- .github/workflows/release-doctor.yml | 2 -- .stats.yml | 2 +- bin/check-release-environment | 4 ---- bin/publish-pypi | 6 +++++- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index aeccf42..a3d82e7 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,6 +12,9 @@ jobs: publish: name: publish runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - uses: actions/checkout@v6 @@ -24,5 +27,3 @@ jobs: - name: Publish to PyPI run: | bash ./bin/publish-pypi - env: - PYPI_TOKEN: ${{ secrets.DEDALUS_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 207944f..1041682 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -17,5 +17,3 @@ jobs: - name: Check release environment run: | bash ./bin/check-release-environment - env: - PYPI_TOKEN: ${{ secrets.DEDALUS_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.stats.yml b/.stats.yml index 5e94783..d1d6236 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: e91c30e20561e6271d4069e7f1576f1f +config_hash: 599eaf8218bcf5573a8acb6ff5af92cf diff --git a/bin/check-release-environment b/bin/check-release-environment index b845b0f..1e951e9 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -2,10 +2,6 @@ errors=() -if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") -fi - lenErrors=${#errors[@]} if [[ lenErrors -gt 0 ]]; then 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 From 972c929aef5d5a2bbd8f6b5b0a2ec3d4902dd3b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 12:58:12 +0000 Subject: [PATCH 4/7] chore(ci): skip uploading artifacts on stainless-internal branches --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b76e3c..6efc518 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,14 +55,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 }} From b8e57a48d562d50b003121ffe8ecb3bfe9182035 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 13:18:19 +0000 Subject: [PATCH 5/7] chore: update placeholder string --- tests/api_resources/test_pets.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/api_resources/test_pets.py b/tests/api_resources/test_pets.py index 5f9c1e6..29a2ae8 100644 --- a/tests/api_resources/test_pets.py +++ b/tests/api_resources/test_pets.py @@ -327,7 +327,7 @@ def test_streaming_response_update_by_id(self, client: Dedalus) -> None: def test_method_upload_image(self, client: Dedalus) -> None: pet = client.pets.upload_image( pet_id=0, - image=b"raw file contents", + image=b"Example data", ) assert_matches_type(PetUploadImageResponse, pet, path=["response"]) @@ -336,7 +336,7 @@ def test_method_upload_image(self, client: Dedalus) -> None: 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", + image=b"Example data", additional_metadata="additionalMetadata", ) assert_matches_type(PetUploadImageResponse, pet, path=["response"]) @@ -346,7 +346,7 @@ def test_method_upload_image_with_all_params(self, client: Dedalus) -> None: 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", + image=b"Example data", ) assert response.is_closed is True @@ -359,7 +359,7 @@ def test_raw_response_upload_image(self, client: Dedalus) -> None: 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", + image=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -680,7 +680,7 @@ async def test_streaming_response_update_by_id(self, async_client: AsyncDedalus) 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", + image=b"Example data", ) assert_matches_type(PetUploadImageResponse, pet, path=["response"]) @@ -689,7 +689,7 @@ async def test_method_upload_image(self, async_client: AsyncDedalus) -> None: 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", + image=b"Example data", additional_metadata="additionalMetadata", ) assert_matches_type(PetUploadImageResponse, pet, path=["response"]) @@ -699,7 +699,7 @@ async def test_method_upload_image_with_all_params(self, async_client: AsyncDeda 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", + image=b"Example data", ) assert response.is_closed is True @@ -712,7 +712,7 @@ async def test_raw_response_upload_image(self, async_client: AsyncDedalus) -> No 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", + image=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" From 706fa9e077164a8e7a4159e5aa536434ac7e6550 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 07:41:02 +0000 Subject: [PATCH 6/7] chore(api): resolving merge conflicts --- .github/CODEOWNERS | 4 + .github/workflows/publish-pypi.yml | 1 + .github/workflows/release-doctor.yml | 3 +- .stats.yml | 8 +- CONTRIBUTING.md | 8 +- LICENSE | 202 +--- README.md | 196 ++-- SECURITY.md | 4 + api.md | 67 +- pyproject.toml | 14 +- release-please-config.json | 5 +- scripts/lint | 2 +- scripts/mock | 52 ++ scripts/test | 46 + src/dedalus/resources/__init__.py | 47 - src/dedalus/resources/pets.py | 872 ------------------ src/dedalus/resources/store/__init__.py | 33 - src/dedalus/resources/store/orders.py | 363 -------- src/dedalus/resources/store/store.py | 177 ---- src/dedalus/resources/users.py | 728 --------------- src/dedalus/types/__init__.py | 25 - src/dedalus/types/category.py | 13 - src/dedalus/types/pet.py | 32 - src/dedalus/types/pet_create_params.py | 33 - .../types/pet_find_by_status_params.py | 12 - .../types/pet_find_by_status_response.py | 10 - src/dedalus/types/pet_find_by_tags_params.py | 14 - .../types/pet_find_by_tags_response.py | 10 - src/dedalus/types/pet_update_by_id_params.py | 15 - src/dedalus/types/pet_update_params.py | 33 - src/dedalus/types/pet_upload_image_params.py | 14 - .../types/pet_upload_image_response.py | 15 - src/dedalus/types/shared/__init__.py | 3 - src/dedalus/types/shared/order.py | 26 - src/dedalus/types/store/__init__.py | 5 - .../types/store/order_create_params.py | 26 - .../types/store_list_inventory_response.py | 8 - src/dedalus/types/user.py | 28 - src/dedalus/types/user_create_params.py | 28 - .../types/user_create_with_list_params.py | 14 - src/dedalus/types/user_login_params.py | 15 - src/dedalus/types/user_login_response.py | 7 - src/dedalus/types/user_param.py | 28 - src/dedalus/types/user_update_params.py | 28 - src/{dedalus => dedalus_sdk}/__init__.py | 4 +- src/{dedalus => dedalus_sdk}/_base_client.py | 36 +- src/{dedalus => dedalus_sdk}/_client.py | 266 +++--- src/{dedalus => dedalus_sdk}/_compat.py | 0 src/{dedalus => dedalus_sdk}/_constants.py | 0 src/{dedalus => dedalus_sdk}/_exceptions.py | 0 src/{dedalus => dedalus_sdk}/_files.py | 0 src/{dedalus => dedalus_sdk}/_models.py | 10 + src/{dedalus => dedalus_sdk}/_qs.py | 0 src/{dedalus => dedalus_sdk}/_resource.py | 0 src/{dedalus => dedalus_sdk}/_response.py | 10 +- src/{dedalus => dedalus_sdk}/_streaming.py | 0 src/{dedalus => dedalus_sdk}/_types.py | 5 +- .../_utils/__init__.py | 0 .../_utils/_compat.py | 0 .../_utils/_datetime_parse.py | 0 src/{dedalus => dedalus_sdk}/_utils/_json.py | 0 src/{dedalus => dedalus_sdk}/_utils/_logs.py | 4 +- src/{dedalus => dedalus_sdk}/_utils/_proxy.py | 0 .../_utils/_reflection.py | 0 .../_utils/_resources_proxy.py | 8 +- .../_utils/_streams.py | 0 src/{dedalus => dedalus_sdk}/_utils/_sync.py | 0 .../_utils/_transform.py | 0 .../_utils/_typing.py | 0 src/{dedalus => dedalus_sdk}/_utils/_utils.py | 0 src/{dedalus => dedalus_sdk}/_version.py | 2 +- src/dedalus_sdk/lib/.keep | 4 + src/dedalus_sdk/pagination.py | 50 + src/{dedalus => dedalus_sdk}/py.typed | 0 src/dedalus_sdk/resources/__init__.py | 19 + src/dedalus_sdk/resources/workspaces.py | 591 ++++++++++++ src/dedalus_sdk/types/__init__.py | 10 + src/dedalus_sdk/types/lifecycle_status.py | 39 + src/dedalus_sdk/types/workspace.py | 22 + .../types/workspace_create_params.py | 17 + src/dedalus_sdk/types/workspace_list.py | 39 + .../types/workspace_list_params.py} | 8 +- .../types/workspace_update_params.py | 19 + tests/api_resources/store/__init__.py | 1 - tests/api_resources/store/test_orders.py | 243 ----- tests/api_resources/test_pets.py | 723 --------------- tests/api_resources/test_store.py | 80 -- tests/api_resources/test_users.py | 620 ------------- tests/api_resources/test_workspaces.py | 438 +++++++++ tests/conftest.py | 6 +- tests/test_client.py | 220 +++-- tests/test_deepcopy.py | 2 +- tests/test_extract_files.py | 4 +- tests/test_files.py | 2 +- tests/test_models.py | 6 +- tests/test_qs.py | 2 +- tests/test_required_args.py | 2 +- tests/test_response.py | 14 +- tests/test_streaming.py | 4 +- tests/test_transform.py | 8 +- tests/test_utils/test_datetime_parse.py | 2 +- tests/test_utils/test_json.py | 4 +- tests/test_utils/test_proxy.py | 2 +- tests/test_utils/test_typing.py | 2 +- tests/utils.py | 8 +- 105 files changed, 1921 insertions(+), 4909 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100755 scripts/mock delete mode 100644 src/dedalus/resources/__init__.py delete mode 100644 src/dedalus/resources/pets.py delete mode 100644 src/dedalus/resources/store/__init__.py delete mode 100644 src/dedalus/resources/store/orders.py delete mode 100644 src/dedalus/resources/store/store.py delete mode 100644 src/dedalus/resources/users.py delete mode 100644 src/dedalus/types/__init__.py delete mode 100644 src/dedalus/types/category.py delete mode 100644 src/dedalus/types/pet.py delete mode 100644 src/dedalus/types/pet_create_params.py delete mode 100644 src/dedalus/types/pet_find_by_status_params.py delete mode 100644 src/dedalus/types/pet_find_by_status_response.py delete mode 100644 src/dedalus/types/pet_find_by_tags_params.py delete mode 100644 src/dedalus/types/pet_find_by_tags_response.py delete mode 100644 src/dedalus/types/pet_update_by_id_params.py delete mode 100644 src/dedalus/types/pet_update_params.py delete mode 100644 src/dedalus/types/pet_upload_image_params.py delete mode 100644 src/dedalus/types/pet_upload_image_response.py delete mode 100644 src/dedalus/types/shared/__init__.py delete mode 100644 src/dedalus/types/shared/order.py delete mode 100644 src/dedalus/types/store/__init__.py delete mode 100644 src/dedalus/types/store/order_create_params.py delete mode 100644 src/dedalus/types/store_list_inventory_response.py delete mode 100644 src/dedalus/types/user.py delete mode 100644 src/dedalus/types/user_create_params.py delete mode 100644 src/dedalus/types/user_create_with_list_params.py delete mode 100644 src/dedalus/types/user_login_params.py delete mode 100644 src/dedalus/types/user_login_response.py delete mode 100644 src/dedalus/types/user_param.py delete mode 100644 src/dedalus/types/user_update_params.py rename src/{dedalus => dedalus_sdk}/__init__.py (95%) rename src/{dedalus => dedalus_sdk}/_base_client.py (98%) rename src/{dedalus => dedalus_sdk}/_client.py (69%) rename src/{dedalus => dedalus_sdk}/_compat.py (100%) rename src/{dedalus => dedalus_sdk}/_constants.py (100%) rename src/{dedalus => dedalus_sdk}/_exceptions.py (100%) rename src/{dedalus => dedalus_sdk}/_files.py (100%) rename src/{dedalus => dedalus_sdk}/_models.py (99%) rename src/{dedalus => dedalus_sdk}/_qs.py (100%) rename src/{dedalus => dedalus_sdk}/_resource.py (100%) rename src/{dedalus => dedalus_sdk}/_response.py (98%) rename src/{dedalus => dedalus_sdk}/_streaming.py (100%) rename src/{dedalus => dedalus_sdk}/_types.py (98%) rename src/{dedalus => dedalus_sdk}/_utils/__init__.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_compat.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_datetime_parse.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_json.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_logs.py (76%) rename src/{dedalus => dedalus_sdk}/_utils/_proxy.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_reflection.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_resources_proxy.py (51%) rename src/{dedalus => dedalus_sdk}/_utils/_streams.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_sync.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_transform.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_typing.py (100%) rename src/{dedalus => dedalus_sdk}/_utils/_utils.py (100%) rename src/{dedalus => dedalus_sdk}/_version.py (84%) create mode 100644 src/dedalus_sdk/lib/.keep create mode 100644 src/dedalus_sdk/pagination.py rename src/{dedalus => dedalus_sdk}/py.typed (100%) create mode 100644 src/dedalus_sdk/resources/__init__.py create mode 100644 src/dedalus_sdk/resources/workspaces.py create mode 100644 src/dedalus_sdk/types/__init__.py create mode 100644 src/dedalus_sdk/types/lifecycle_status.py create mode 100644 src/dedalus_sdk/types/workspace.py create mode 100644 src/dedalus_sdk/types/workspace_create_params.py create mode 100644 src/dedalus_sdk/types/workspace_list.py rename src/{dedalus/types/category_param.py => dedalus_sdk/types/workspace_list_params.py} (59%) create mode 100644 src/dedalus_sdk/types/workspace_update_params.py delete mode 100644 tests/api_resources/store/__init__.py delete mode 100644 tests/api_resources/store/test_orders.py delete mode 100644 tests/api_resources/test_pets.py delete mode 100644 tests/api_resources/test_store.py delete mode 100644 tests/api_resources/test_users.py create mode 100644 tests/api_resources/test_workspaces.py 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/publish-pypi.yml b/.github/workflows/publish-pypi.yml index a3d82e7..7e1e57e 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -12,6 +12,7 @@ jobs: publish: name: publish runs-on: ubuntu-latest + environment: production permissions: contents: read id-token: write diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 1041682..07a625c 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -1,6 +1,6 @@ name: Release Doctor on: - pull_request: + push: branches: - main workflow_dispatch: @@ -9,6 +9,7 @@ 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: diff --git a/.stats.yml b/.stats.yml index d1d6236..486e14d 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: 599eaf8218bcf5573a8acb6ff5af92cf +configured_endpoints: 5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/dedalus-labs%2Fdedalus-07eb2abb4e9227720def83bb614d131736ee03492cd320a023a848817edbdbda.yml +openapi_spec_hash: 85b9a0b888ad84e96f096c6b57f91065 +config_hash: edb87a2030c8f6ea0e1a1d1cc8461322 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1eda1e..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 @@ -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 ``` 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 951ff5a..edc4f1b 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,14 @@ 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. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=dedalus-mcp&config=eyJuYW1lIjoiZGVkYWx1cy1tY3AiLCJ0cmFuc3BvcnQiOiJodHRwIiwidXJsIjoiaHR0cHM6Ly9kZWRhbHVzLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7ImFwaV9rZXkiOiJNeSBBUEkgS2V5In19) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](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) +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=dedalus-mcp&config=eyJuYW1lIjoiZGVkYWx1cy1tY3AiLCJ0cmFuc3BvcnQiOiJodHRwIiwidXJsIjoiaHR0cHM6Ly9kZWRhbHVzLnN0bG1jcC5jb20iLCJoZWFkZXJzIjp7IngtYXBpLWtleSI6Ik15IFggQVBJIEtleSIsIngtZGVkYWx1cy1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](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 @@ -35,24 +35,25 @@ 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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, ) -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 @@ -61,20 +62,21 @@ 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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, ) - print(order.id) + print(workspace.workspace_id) asyncio.run(main()) @@ -98,21 +100,22 @@ 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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, ) - print(order.id) + print(workspace.workspace_id) asyncio.run(main()) @@ -127,46 +130,97 @@ 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 + +List methods in the Dedalus API are paginated. -Nested parameters are dictionaries, typed using `TypedDict`, for example: +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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, + ) +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) @@ -194,7 +248,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( @@ -203,7 +257,12 @@ client = Dedalus( ) # Or, configure per-request: -client.with_options(max_retries=5).store.list_inventory() +client.with_options(max_retries=5).workspaces.create( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, +) ``` ### Timeouts @@ -212,7 +271,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( @@ -226,7 +285,12 @@ client = Dedalus( ) # Override per-request: -client.with_options(timeout=5.0).store.list_inventory() +client.with_options(timeout=5.0).workspaces.create( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, +) ``` On timeout, an `APITimeoutError` is thrown. @@ -264,19 +328,24 @@ 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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, +) 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/dedalus-labs/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/dedalus-labs/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` @@ -285,7 +354,12 @@ 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( + cpus=1, + image_version="noble@2026-03-01.1", + memory_mib=2048, + storage_gib=20, +) as response: print(response.headers.get("X-My-Header")) for line in response.iter_lines(): @@ -338,7 +412,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 @@ -361,7 +435,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 @@ -389,8 +463,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..962bb46 100644 --- a/api.md +++ b/api.md @@ -1,68 +1,15 @@ -# Shared Types - -```python -from dedalus.types import Order -``` - -# Pets - -Types: - -```python -from dedalus.types import ( - Category, - Pet, - PetFindByStatusResponse, - PetFindByTagsResponse, - PetUploadImageResponse, -) -``` - -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 - -# Store - -Types: - -```python -from dedalus.types import StoreListInventoryResponse -``` - -Methods: - -- client.store.list_inventory() -> StoreListInventoryResponse - -## Orders - -Methods: - -- client.store.orders.create(\*\*params) -> Order -- client.store.orders.retrieve(order_id) -> Order -- client.store.orders.delete(order_id) -> None - -# Users +# Workspaces Types: ```python -from dedalus.types import User, UserLoginResponse +from dedalus_sdk.types import CreateParams, LifecycleStatus, UpdateParams, Workspace, WorkspaceList ``` 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.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 diff --git a/pyproject.toml b/pyproject.toml index 791f2b6..1cf6d8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [project] 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 = [ @@ -33,7 +33,7 @@ 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] @@ -86,7 +86,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) @@ -154,7 +154,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 +246,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 index 16d61c9..65fbc85 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -59,8 +59,11 @@ "hidden": true } ], + "reviewers": [ + "@windsornguyen" + ], "release-type": "python", "extra-files": [ - "src/dedalus/_version.py" + "src/dedalus_sdk/_version.py" ] } \ No newline at end of file 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 8978816..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/dedalus-labs/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/dedalus-labs/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/dedalus-labs/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/dedalus-labs/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/orders.py b/src/dedalus/resources/store/orders.py deleted file mode 100644 index b0163fe..0000000 --- a/src/dedalus/resources/store/orders.py +++ /dev/null @@ -1,363 +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 - -import httpx - -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 ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - 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"] - - -class OrdersResource(SyncAPIResource): - """Access to Petstore orders""" - - @cached_property - def with_raw_response(self) -> OrdersResourceWithRawResponse: - """ - 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 OrdersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> OrdersResourceWithStreamingResponse: - """ - 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 OrdersResourceWithStreamingResponse(self) - - def create( - self, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - Place a new order in the store - - Args: - status: Order Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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( - "/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, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Order, - ) - - def retrieve( - self, - order_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, - ) -> Order: - """For valid response try integer IDs with value <= 5 or > 10. - - Other values will - generate exceptions. - - 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"/store/order/{order_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Order, - ) - - def delete( - self, - order_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: - """For valid response try integer IDs with value < 1000. - - Anything above 1000 or - nonintegers will generate API errors - - 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"/store/order/{order_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncOrdersResource(AsyncAPIResource): - """Access to Petstore orders""" - - @cached_property - def with_raw_response(self) -> AsyncOrdersResourceWithRawResponse: - """ - 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 AsyncOrdersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncOrdersResourceWithStreamingResponse: - """ - 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 AsyncOrdersResourceWithStreamingResponse(self) - - async def create( - self, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - Place a new order in the store - - Args: - status: Order Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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( - "/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, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Order, - ) - - async def retrieve( - self, - order_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, - ) -> Order: - """For valid response try integer IDs with value <= 5 or > 10. - - Other values will - generate exceptions. - - 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"/store/order/{order_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=Order, - ) - - async def delete( - self, - order_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: - """For valid response try integer IDs with value < 1000. - - Anything above 1000 or - nonintegers will generate API errors - - 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"/store/order/{order_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class OrdersResourceWithRawResponse: - def __init__(self, orders: OrdersResource) -> None: - self._orders = orders - - self.create = to_raw_response_wrapper( - orders.create, - ) - self.retrieve = to_raw_response_wrapper( - orders.retrieve, - ) - self.delete = to_raw_response_wrapper( - orders.delete, - ) - - -class AsyncOrdersResourceWithRawResponse: - def __init__(self, orders: AsyncOrdersResource) -> None: - self._orders = orders - - self.create = async_to_raw_response_wrapper( - orders.create, - ) - self.retrieve = async_to_raw_response_wrapper( - orders.retrieve, - ) - self.delete = async_to_raw_response_wrapper( - orders.delete, - ) - - -class OrdersResourceWithStreamingResponse: - def __init__(self, orders: OrdersResource) -> None: - self._orders = orders - - self.create = to_streamed_response_wrapper( - orders.create, - ) - self.retrieve = to_streamed_response_wrapper( - orders.retrieve, - ) - self.delete = to_streamed_response_wrapper( - orders.delete, - ) - - -class AsyncOrdersResourceWithStreamingResponse: - def __init__(self, orders: AsyncOrdersResource) -> None: - self._orders = orders - - self.create = async_to_streamed_response_wrapper( - orders.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - orders.retrieve, - ) - self.delete = async_to_streamed_response_wrapper( - orders.delete, - ) diff --git a/src/dedalus/resources/store/store.py b/src/dedalus/resources/store/store.py deleted file mode 100644 index 60212c3..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/dedalus-labs/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/dedalus-labs/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/dedalus-labs/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/dedalus-labs/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/resources/users.py b/src/dedalus/resources/users.py deleted file mode 100644 index a367e1b..0000000 --- a/src/dedalus/resources/users.py +++ /dev/null @@ -1,728 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable - -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 ( - 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 - -__all__ = ["UsersResource", "AsyncUsersResource"] - - -class UsersResource(SyncAPIResource): - """Operations about user""" - - @cached_property - def with_raw_response(self) -> UsersResourceWithRawResponse: - """ - 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 UsersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> UsersResourceWithStreamingResponse: - """ - 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 UsersResourceWithStreamingResponse(self) - - def create( - self, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - This can only be done by the logged in user. - - Args: - user_status: User Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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( - "/user", - 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_create_params.UserCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - def retrieve( - self, - username: 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: - """ - Get user by user name - - 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 username: - raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") - return self._get( - f"/user/{username}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - def update( - self, - existing_username: 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - This can only be done by the logged in user. - - Args: - user_status: User Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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 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, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def delete( - self, - username: 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: - """ - This can only be done by the logged in user. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not username: - raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/user/{username}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def create_with_list( - self, - *, - items: Iterable[UserParam] | 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: - """ - Creates list of users with given input array - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/user/createWithList", - body=maybe_transform(items, Iterable[UserParam]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - def login( - self, - *, - password: str | Omit = omit, - username: 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, - ) -> str: - """ - Logs user into the system - - 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 - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - 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", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncUsersResource(AsyncAPIResource): - """Operations about user""" - - @cached_property - def with_raw_response(self) -> AsyncUsersResourceWithRawResponse: - """ - 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 AsyncUsersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse: - """ - 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 AsyncUsersResourceWithStreamingResponse(self) - - async def create( - self, - *, - 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - This can only be done by the logged in user. - - Args: - user_status: User Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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( - "/user", - 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_create_params.UserCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - async def retrieve( - self, - username: 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: - """ - Get user by user name - - 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 username: - raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") - return await self._get( - f"/user/{username}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - async def update( - self, - existing_username: 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, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this 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: - """ - This can only be done by the logged in user. - - Args: - user_status: User Status - - extra_headers: Send extra headers - - extra_query: Add additional query parameters 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 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, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def delete( - self, - username: 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: - """ - This can only be done by the logged in user. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not username: - raise ValueError(f"Expected a non-empty value for `username` but received {username!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/user/{username}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def create_with_list( - self, - *, - items: Iterable[UserParam] | 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: - """ - Creates list of users with given input array - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/user/createWithList", - body=await async_maybe_transform(items, Iterable[UserParam]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=User, - ) - - async def login( - self, - *, - password: str | Omit = omit, - username: 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, - ) -> str: - """ - Logs user into the system - - 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 - - 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( - "/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", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class UsersResourceWithRawResponse: - def __init__(self, users: UsersResource) -> None: - self._users = users - - self.create = to_raw_response_wrapper( - users.create, - ) - self.retrieve = to_raw_response_wrapper( - users.retrieve, - ) - self.update = to_raw_response_wrapper( - users.update, - ) - self.delete = to_raw_response_wrapper( - users.delete, - ) - self.create_with_list = to_raw_response_wrapper( - users.create_with_list, - ) - self.login = to_raw_response_wrapper( - users.login, - ) - self.logout = to_raw_response_wrapper( - users.logout, - ) - - -class AsyncUsersResourceWithRawResponse: - def __init__(self, users: AsyncUsersResource) -> None: - self._users = users - - self.create = async_to_raw_response_wrapper( - users.create, - ) - self.retrieve = async_to_raw_response_wrapper( - users.retrieve, - ) - self.update = async_to_raw_response_wrapper( - users.update, - ) - self.delete = async_to_raw_response_wrapper( - users.delete, - ) - self.create_with_list = async_to_raw_response_wrapper( - users.create_with_list, - ) - self.login = async_to_raw_response_wrapper( - users.login, - ) - self.logout = async_to_raw_response_wrapper( - users.logout, - ) - - -class UsersResourceWithStreamingResponse: - def __init__(self, users: UsersResource) -> None: - self._users = users - - self.create = to_streamed_response_wrapper( - users.create, - ) - self.retrieve = to_streamed_response_wrapper( - users.retrieve, - ) - self.update = to_streamed_response_wrapper( - users.update, - ) - self.delete = to_streamed_response_wrapper( - users.delete, - ) - self.create_with_list = to_streamed_response_wrapper( - users.create_with_list, - ) - self.login = to_streamed_response_wrapper( - users.login, - ) - self.logout = to_streamed_response_wrapper( - users.logout, - ) - - -class AsyncUsersResourceWithStreamingResponse: - def __init__(self, users: AsyncUsersResource) -> None: - self._users = users - - self.create = async_to_streamed_response_wrapper( - users.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - users.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - users.update, - ) - self.delete = async_to_streamed_response_wrapper( - users.delete, - ) - self.create_with_list = async_to_streamed_response_wrapper( - users.create_with_list, - ) - self.login = async_to_streamed_response_wrapper( - users.login, - ) - self.logout = async_to_streamed_response_wrapper( - users.logout, - ) 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 69% rename from src/dedalus/_client.py rename to src/dedalus_sdk/_client.py index 4665240..ecbf112 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,22 +33,24 @@ ) 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 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 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, timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, @@ -68,20 +72,27 @@ 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 + 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 +105,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) + self._idempotency_header = "Idempotency-Key" @cached_property - def store(self) -> StoreResource: - """Access to Petstore orders""" - from .resources.store import StoreResource + def workspaces(self) -> WorkspacesResource: + from .resources.workspaces import WorkspacesResource - return StoreResource(self) - - @cached_property - def users(self) -> UsersResource: - """Operations about user""" - from .resources.users import UsersResource - - return UsersResource(self) + return WorkspacesResource(self) @cached_property def with_raw_response(self) -> DedalusWithRawResponse: @@ -128,11 +126,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 +153,28 @@ 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, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, @@ -181,6 +209,8 @@ 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, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -230,12 +260,16 @@ 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 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, timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, @@ -257,20 +291,27 @@ 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 + 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 +324,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) - - @cached_property - def store(self) -> AsyncStoreResource: - """Access to Petstore orders""" - from .resources.store import AsyncStoreResource - - return AsyncStoreResource(self) + self._idempotency_header = "Idempotency-Key" @cached_property - def users(self) -> AsyncUsersResource: - """Operations about user""" - from .resources.users import AsyncUsersResource + def workspaces(self) -> AsyncWorkspacesResource: + from .resources.workspaces import AsyncWorkspacesResource - return AsyncUsersResource(self) + return AsyncWorkspacesResource(self) @cached_property def with_raw_response(self) -> AsyncDedalusWithRawResponse: @@ -317,11 +345,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 +372,28 @@ 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, base_url: str | httpx.URL | None = None, timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, @@ -370,6 +428,8 @@ 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, base_url=base_url or self.base_url, timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, http_client=http_client, @@ -424,25 +484,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 + def workspaces(self) -> workspaces.WorkspacesResourceWithRawResponse: + from .resources.workspaces import WorkspacesResourceWithRawResponse - 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 - - return UsersResourceWithRawResponse(self._client.users) + return WorkspacesResourceWithRawResponse(self._client.workspaces) class AsyncDedalusWithRawResponse: @@ -452,25 +497,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 +510,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 - - return StoreResourceWithStreamingResponse(self._client.store) - - @cached_property - def users(self) -> users.UsersResourceWithStreamingResponse: - """Operations about user""" - from .resources.users import UsersResourceWithStreamingResponse + def workspaces(self) -> workspaces.WorkspacesResourceWithStreamingResponse: + from .resources.workspaces import WorkspacesResourceWithStreamingResponse - return UsersResourceWithStreamingResponse(self._client.users) + return WorkspacesResourceWithStreamingResponse(self._client.workspaces) class AsyncDedalusWithStreamedResponse: @@ -508,25 +523,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 100% rename from src/dedalus/_compat.py rename to src/dedalus_sdk/_compat.py 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 84% rename from src/dedalus/_version.py rename to src/dedalus_sdk/_version.py index 08dd84a..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" +__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..37b015b --- /dev/null +++ b/src/dedalus_sdk/pagination.py @@ -0,0 +1,50 @@ +# 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"] + +_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}) 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.py b/src/dedalus_sdk/resources/workspaces.py new file mode 100644 index 0000000..a43237a --- /dev/null +++ b/src/dedalus_sdk/resources/workspaces.py @@ -0,0 +1,591 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +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 .._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 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 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, + *, + cpus: int, + image_version: str, + memory_mib: int, + storage_gib: 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, + idempotency_key: str | None = None, + ) -> Workspace: + """ + Create 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 + """ + return self._post( + "/v1/workspaces", + body=maybe_transform( + { + "cpus": cpus, + "image_version": image_version, + "memory_mib": memory_mib, + "storage_gib": storage_gib, + }, + 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, + cpus: int | Omit = omit, + memory_mib: int | Omit = omit, + storage_gib: 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, + idempotency_key: str | None = None, + ) -> Workspace: + """ + Update 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._patch( + f"/v1/workspaces/{workspace_id}", + body=maybe_transform( + { + "cpus": cpus, + "memory_mib": memory_mib, + "storage_gib": storage_gib, + }, + 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 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, + *, + cpus: int, + image_version: str, + memory_mib: int, + storage_gib: 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, + idempotency_key: str | None = None, + ) -> Workspace: + """ + Create 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 + """ + return await self._post( + "/v1/workspaces", + body=await async_maybe_transform( + { + "cpus": cpus, + "image_version": image_version, + "memory_mib": memory_mib, + "storage_gib": storage_gib, + }, + 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, + cpus: int | Omit = omit, + memory_mib: int | Omit = omit, + storage_gib: 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, + idempotency_key: str | None = None, + ) -> Workspace: + """ + Update 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._patch( + f"/v1/workspaces/{workspace_id}", + body=await async_maybe_transform( + { + "cpus": cpus, + "memory_mib": memory_mib, + "storage_gib": storage_gib, + }, + 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, + ) + + +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, + ) + + +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, + ) + + +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, + ) diff --git a/src/dedalus_sdk/types/__init__.py b/src/dedalus_sdk/types/__init__.py new file mode 100644 index 0000000..c2e59c4 --- /dev/null +++ b/src/dedalus_sdk/types/__init__.py @@ -0,0 +1,10 @@ +# 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 diff --git a/src/dedalus_sdk/types/lifecycle_status.py b/src/dedalus_sdk/types/lifecycle_status.py new file mode 100644 index 0000000..480fb94 --- /dev/null +++ b/src/dedalus_sdk/types/lifecycle_status.py @@ -0,0 +1,39 @@ +# 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 + + observed_revision: str + + phase: Literal[ + "accepted", + "placement_pending", + "starting", + "running", + "stopping", + "sleeping", + "destroying", + "destroyed", + "failed", + ] + + reason: str + + retryable: bool + + revision: str + + assigned_host: Optional[str] = None + + last_error: Optional[str] = None diff --git a/src/dedalus_sdk/types/workspace.py b/src/dedalus_sdk/types/workspace.py new file mode 100644 index 0000000..58004e1 --- /dev/null +++ b/src/dedalus_sdk/types/workspace.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel +from .lifecycle_status import LifecycleStatus + +__all__ = ["Workspace"] + + +class Workspace(BaseModel): + desired_state: Literal["active", "inactive", "destroyed"] + + status: LifecycleStatus + + 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..6a505a5 --- /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): + cpus: Required[int] + + image_version: Required[str] + + memory_mib: Required[int] + + storage_gib: Required[int] diff --git a/src/dedalus_sdk/types/workspace_list.py b/src/dedalus_sdk/types/workspace_list.py new file mode 100644 index 0000000..31ce441 --- /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): + cpus: int + + created_at: datetime + + desired_state: Literal["active", "inactive", "destroyed"] + + memory_mib: int + + status: LifecycleStatus + + storage_gib: int + + workspace_id: str + + image_version: Optional[str] = None + + +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/types/category_param.py b/src/dedalus_sdk/types/workspace_list_params.py similarity index 59% rename from src/dedalus/types/category_param.py rename to src/dedalus_sdk/types/workspace_list_params.py index 2cdf264..f3e43d5 100644 --- a/src/dedalus/types/category_param.py +++ b/src/dedalus_sdk/types/workspace_list_params.py @@ -4,10 +4,10 @@ from typing_extensions import TypedDict -__all__ = ["CategoryParam"] +__all__ = ["WorkspaceListParams"] -class CategoryParam(TypedDict, total=False): - id: int +class WorkspaceListParams(TypedDict, total=False): + cursor: str - name: 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..5688497 --- /dev/null +++ b/src/dedalus_sdk/types/workspace_update_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["WorkspaceUpdateParams"] + + +class WorkspaceUpdateParams(TypedDict, total=False): + if_match: Required[Annotated[str, PropertyInfo(alias="If-Match")]] + + cpus: int + + memory_mib: int + + storage_gib: int diff --git a/tests/api_resources/store/__init__.py b/tests/api_resources/store/__init__.py deleted file mode 100644 index fd8019a..0000000 --- a/tests/api_resources/store/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/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 29a2ae8..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"Example data", - ) - 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"Example data", - 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"Example data", - ) - - 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"Example data", - ) 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"Example data", - ) - 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"Example data", - 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"Example data", - ) - - 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"Example data", - ) 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..3191b83 --- /dev/null +++ b/tests/api_resources/test_workspaces.py @@ -0,0 +1,438 @@ +# 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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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", + cpus=0, + memory_mib=0, + storage_gib=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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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", + cpus=0, + memory_mib=0, + storage_gib=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/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..b11a029 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,31 @@ 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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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 +933,17 @@ 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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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 +959,20 @@ 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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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 +988,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(extra_headers={"x-stainless-retry-count": "42"}) + response = client.workspaces.with_raw_response.create( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=0, + extra_headers={"x-stainless-retry-count": "42"}, + ) assert response.http_request.headers.get("x-stainless-retry-count") == "42" @@ -1173,10 +1231,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 +1349,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 +1636,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 +1850,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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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 +1899,17 @@ 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( + cpus=0, image_version="image_version", memory_mib=0, storage_gib=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 +1925,20 @@ 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( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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 +1954,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(extra_headers={"x-stainless-retry-count": "42"}) + response = await client.workspaces.with_raw_response.create( + cpus=0, + image_version="image_version", + memory_mib=0, + storage_gib=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) From 090eaf9857eff7a3cae8938a9bf8e68c8972ecc1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 07:41:14 +0000 Subject: [PATCH 7/7] release: 0.0.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 15 +++++++++++++++ pyproject.toml | 2 +- src/dedalus_sdk/_version.py | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1332969..c7159c1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1" + ".": "0.0.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..42861db --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +## 0.0.2 (2026-03-10) + +Full Changelog: [v0.0.1...v0.0.2](https://github.com/dedalus-labs/dedalus-python/compare/v0.0.1...v0.0.2) + +### 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)) +* update placeholder string ([b8e57a4](https://github.com/dedalus-labs/dedalus-python/commit/b8e57a48d562d50b003121ffe8ecb3bfe9182035)) +* 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/pyproject.toml b/pyproject.toml index 1cf6d8f..6fd6768 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dedalus-sdk" -version = "0.0.1" +version = "0.0.2" description = "The official Python library for the Dedalus API" dynamic = ["readme"] license = "MIT" diff --git a/src/dedalus_sdk/_version.py b/src/dedalus_sdk/_version.py index 02910e4..96bd39b 100644 --- a/src/dedalus_sdk/_version.py +++ b/src/dedalus_sdk/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "dedalus_sdk" -__version__ = "0.0.1" # x-release-please-version +__version__ = "0.0.2" # x-release-please-version