From 0e4d24129716e977791255bd26561a97ed3191dc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 16:23:14 +0000 Subject: [PATCH 001/101] chore: update SDK settings --- .github/workflows/publish-pypi.yml | 31 +++++++++ .github/workflows/release-doctor.yml | 21 ++++++ .release-please-manifest.json | 3 + .stats.yml | 2 +- CONTRIBUTING.md | 4 +- README.md | 10 +-- bin/check-release-environment | 21 ++++++ pyproject.toml | 6 +- release-please-config.json | 66 +++++++++++++++++++ src/knock_mapi/_version.py | 2 +- src/knock_mapi/resources/api_keys.py | 8 +-- src/knock_mapi/resources/auth.py | 8 +-- src/knock_mapi/resources/channel_groups.py | 8 +-- src/knock_mapi/resources/channels.py | 8 +-- src/knock_mapi/resources/commits.py | 8 +-- src/knock_mapi/resources/email_layouts.py | 8 +-- src/knock_mapi/resources/environments.py | 8 +-- src/knock_mapi/resources/message_types.py | 8 +-- src/knock_mapi/resources/partials.py | 8 +-- src/knock_mapi/resources/translations.py | 8 +-- src/knock_mapi/resources/variables.py | 8 +-- src/knock_mapi/resources/workflows/steps.py | 8 +-- .../resources/workflows/workflows.py | 8 +-- 23 files changed, 206 insertions(+), 64 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..4208e2a --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,31 @@ +# 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/knocklabs/knock-mgmt-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@v4 + + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Publish to PyPI + run: | + bash ./bin/publish-pypi + env: + PYPI_TOKEN: ${{ secrets.KNOCK_MGMT_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..5a24cca --- /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 == 'knocklabs/knock-mgmt-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + PYPI_TOKEN: ${{ secrets.KNOCK_MGMT_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..c476280 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.1-alpha.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 02525ab..8eebb3f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 35 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-305e73d67d2964dc9148b0f091d040e1d2899960af5815ecac64089110085804.yml openapi_spec_hash: 90b9e75af20d6209e1a294d7227120fc -config_hash: bb4cfc20c3c1e1a40c6a9f4c5ea209df +config_hash: 24265f2774d9e93e37cccc0726c8555f diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc3ee0f..848b4db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,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/knock-mapi-python.git +$ pip install git+ssh://git@github.com/knocklabs/knock-mgmt-python.git ``` Alternatively, you can build from source and install the wheel file: @@ -121,7 +121,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/knock-mapi-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/knocklabs/knock-mgmt-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 0a09cc2..bd53cd0 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ The REST API documentation can be found on [docs.knock.app](https://docs.knock.a ## Installation ```sh -# install from this staging repo -pip install git+ssh://git@github.com/stainless-sdks/knock-mapi-python.git +# install from the production repo +pip install git+ssh://git@github.com/knocklabs/knock-mgmt-python.git ``` > [!NOTE] @@ -316,9 +316,9 @@ workflow = response.parse() # get the object that `workflows.list()` would have print(workflow.valid) ``` -These methods return an [`APIResponse`](https://github.com/stainless-sdks/knock-mapi-python/tree/main/src/knock_mapi/_response.py) object. +These methods return an [`APIResponse`](https://github.com/knocklabs/knock-mgmt-python/tree/main/src/knock_mapi/_response.py) object. -The async client returns an [`AsyncAPIResponse`](https://github.com/stainless-sdks/knock-mapi-python/tree/main/src/knock_mapi/_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/knocklabs/knock-mgmt-python/tree/main/src/knock_mapi/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. #### `.with_streaming_response` @@ -424,7 +424,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/knock-mapi-python/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/knocklabs/knock-mgmt-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..40ee32e --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${PYPI_TOKEN}" ]; then + errors+=("The KNOCK_MGMT_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 a3caaee..ca332b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,8 +34,8 @@ classifiers = [ ] [project.urls] -Homepage = "https://github.com/stainless-sdks/knock-mapi-python" -Repository = "https://github.com/stainless-sdks/knock-mapi-python" +Homepage = "https://github.com/knocklabs/knock-mgmt-python" +Repository = "https://github.com/knocklabs/knock-mgmt-python" [tool.rye] @@ -121,7 +121,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/knock-mapi-python/tree/main/\g<2>)' +replacement = '[\1](https://github.com/knocklabs/knock-mgmt-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..a77036b --- /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/knock_mapi/_version.py" + ] +} \ No newline at end of file diff --git a/src/knock_mapi/_version.py b/src/knock_mapi/_version.py index a7e5bf1..32c8602 100644 --- a/src/knock_mapi/_version.py +++ b/src/knock_mapi/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "knock_mapi" -__version__ = "0.0.1-alpha.0" +__version__ = "0.0.1-alpha.0" # x-release-please-version diff --git a/src/knock_mapi/resources/api_keys.py b/src/knock_mapi/resources/api_keys.py index 7dd93b1..4ead617 100644 --- a/src/knock_mapi/resources/api_keys.py +++ b/src/knock_mapi/resources/api_keys.py @@ -28,7 +28,7 @@ def with_raw_response(self) -> APIKeysResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return APIKeysResourceWithRawResponse(self) @@ -37,7 +37,7 @@ def with_streaming_response(self) -> APIKeysResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return APIKeysResourceWithStreamingResponse(self) @@ -88,7 +88,7 @@ def with_raw_response(self) -> AsyncAPIKeysResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncAPIKeysResourceWithRawResponse(self) @@ -97,7 +97,7 @@ def with_streaming_response(self) -> AsyncAPIKeysResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncAPIKeysResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/auth.py b/src/knock_mapi/resources/auth.py index 83e278c..3da0bbb 100644 --- a/src/knock_mapi/resources/auth.py +++ b/src/knock_mapi/resources/auth.py @@ -26,7 +26,7 @@ def with_raw_response(self) -> AuthResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AuthResourceWithRawResponse(self) @@ -35,7 +35,7 @@ def with_streaming_response(self) -> AuthResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AuthResourceWithStreamingResponse(self) @@ -66,7 +66,7 @@ def with_raw_response(self) -> AsyncAuthResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncAuthResourceWithRawResponse(self) @@ -75,7 +75,7 @@ def with_streaming_response(self) -> AsyncAuthResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncAuthResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/channel_groups.py b/src/knock_mapi/resources/channel_groups.py index 74c3b7c..8797bb8 100644 --- a/src/knock_mapi/resources/channel_groups.py +++ b/src/knock_mapi/resources/channel_groups.py @@ -29,7 +29,7 @@ def with_raw_response(self) -> ChannelGroupsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return ChannelGroupsResourceWithRawResponse(self) @@ -38,7 +38,7 @@ def with_streaming_response(self) -> ChannelGroupsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return ChannelGroupsResourceWithStreamingResponse(self) @@ -103,7 +103,7 @@ def with_raw_response(self) -> AsyncChannelGroupsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncChannelGroupsResourceWithRawResponse(self) @@ -112,7 +112,7 @@ def with_streaming_response(self) -> AsyncChannelGroupsResourceWithStreamingResp """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncChannelGroupsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/channels.py b/src/knock_mapi/resources/channels.py index 170f1ca..3f650b1 100644 --- a/src/knock_mapi/resources/channels.py +++ b/src/knock_mapi/resources/channels.py @@ -29,7 +29,7 @@ def with_raw_response(self) -> ChannelsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return ChannelsResourceWithRawResponse(self) @@ -38,7 +38,7 @@ def with_streaming_response(self) -> ChannelsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return ChannelsResourceWithStreamingResponse(self) @@ -103,7 +103,7 @@ def with_raw_response(self) -> AsyncChannelsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncChannelsResourceWithRawResponse(self) @@ -112,7 +112,7 @@ def with_streaming_response(self) -> AsyncChannelsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncChannelsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index 4e02cac..c10c5c5 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -32,7 +32,7 @@ def with_raw_response(self) -> CommitsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return CommitsResourceWithRawResponse(self) @@ -41,7 +41,7 @@ def with_streaming_response(self) -> CommitsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return CommitsResourceWithStreamingResponse(self) @@ -274,7 +274,7 @@ def with_raw_response(self) -> AsyncCommitsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncCommitsResourceWithRawResponse(self) @@ -283,7 +283,7 @@ def with_streaming_response(self) -> AsyncCommitsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncCommitsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/email_layouts.py b/src/knock_mapi/resources/email_layouts.py index 213de0f..d527bf9 100644 --- a/src/knock_mapi/resources/email_layouts.py +++ b/src/knock_mapi/resources/email_layouts.py @@ -36,7 +36,7 @@ def with_raw_response(self) -> EmailLayoutsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return EmailLayoutsResourceWithRawResponse(self) @@ -45,7 +45,7 @@ def with_streaming_response(self) -> EmailLayoutsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return EmailLayoutsResourceWithStreamingResponse(self) @@ -288,7 +288,7 @@ def with_raw_response(self) -> AsyncEmailLayoutsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncEmailLayoutsResourceWithRawResponse(self) @@ -297,7 +297,7 @@ def with_streaming_response(self) -> AsyncEmailLayoutsResourceWithStreamingRespo """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncEmailLayoutsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/environments.py b/src/knock_mapi/resources/environments.py index a43c907..4351ac5 100644 --- a/src/knock_mapi/resources/environments.py +++ b/src/knock_mapi/resources/environments.py @@ -29,7 +29,7 @@ def with_raw_response(self) -> EnvironmentsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return EnvironmentsResourceWithRawResponse(self) @@ -38,7 +38,7 @@ def with_streaming_response(self) -> EnvironmentsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return EnvironmentsResourceWithStreamingResponse(self) @@ -136,7 +136,7 @@ def with_raw_response(self) -> AsyncEnvironmentsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncEnvironmentsResourceWithRawResponse(self) @@ -145,7 +145,7 @@ def with_streaming_response(self) -> AsyncEnvironmentsResourceWithStreamingRespo """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncEnvironmentsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/message_types.py b/src/knock_mapi/resources/message_types.py index 375f974..8abff16 100644 --- a/src/knock_mapi/resources/message_types.py +++ b/src/knock_mapi/resources/message_types.py @@ -36,7 +36,7 @@ def with_raw_response(self) -> MessageTypesResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return MessageTypesResourceWithRawResponse(self) @@ -45,7 +45,7 @@ def with_streaming_response(self) -> MessageTypesResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return MessageTypesResourceWithStreamingResponse(self) @@ -289,7 +289,7 @@ def with_raw_response(self) -> AsyncMessageTypesResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncMessageTypesResourceWithRawResponse(self) @@ -298,7 +298,7 @@ def with_streaming_response(self) -> AsyncMessageTypesResourceWithStreamingRespo """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncMessageTypesResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/partials.py b/src/knock_mapi/resources/partials.py index ee61bf3..5395a36 100644 --- a/src/knock_mapi/resources/partials.py +++ b/src/knock_mapi/resources/partials.py @@ -31,7 +31,7 @@ def with_raw_response(self) -> PartialsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return PartialsResourceWithRawResponse(self) @@ -40,7 +40,7 @@ def with_streaming_response(self) -> PartialsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return PartialsResourceWithStreamingResponse(self) @@ -279,7 +279,7 @@ def with_raw_response(self) -> AsyncPartialsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncPartialsResourceWithRawResponse(self) @@ -288,7 +288,7 @@ def with_streaming_response(self) -> AsyncPartialsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncPartialsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/translations.py b/src/knock_mapi/resources/translations.py index 678a0ee..1df7087 100644 --- a/src/knock_mapi/resources/translations.py +++ b/src/knock_mapi/resources/translations.py @@ -39,7 +39,7 @@ def with_raw_response(self) -> TranslationsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return TranslationsResourceWithRawResponse(self) @@ -48,7 +48,7 @@ def with_streaming_response(self) -> TranslationsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return TranslationsResourceWithStreamingResponse(self) @@ -327,7 +327,7 @@ def with_raw_response(self) -> AsyncTranslationsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncTranslationsResourceWithRawResponse(self) @@ -336,7 +336,7 @@ def with_streaming_response(self) -> AsyncTranslationsResourceWithStreamingRespo """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncTranslationsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/variables.py b/src/knock_mapi/resources/variables.py index 95cf469..a211ac9 100644 --- a/src/knock_mapi/resources/variables.py +++ b/src/knock_mapi/resources/variables.py @@ -29,7 +29,7 @@ def with_raw_response(self) -> VariablesResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return VariablesResourceWithRawResponse(self) @@ -38,7 +38,7 @@ def with_streaming_response(self) -> VariablesResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return VariablesResourceWithStreamingResponse(self) @@ -105,7 +105,7 @@ def with_raw_response(self) -> AsyncVariablesResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncVariablesResourceWithRawResponse(self) @@ -114,7 +114,7 @@ def with_streaming_response(self) -> AsyncVariablesResourceWithStreamingResponse """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncVariablesResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/workflows/steps.py b/src/knock_mapi/resources/workflows/steps.py index cebf1cf..39da217 100644 --- a/src/knock_mapi/resources/workflows/steps.py +++ b/src/knock_mapi/resources/workflows/steps.py @@ -30,7 +30,7 @@ def with_raw_response(self) -> StepsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return StepsResourceWithRawResponse(self) @@ -39,7 +39,7 @@ def with_streaming_response(self) -> StepsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return StepsResourceWithStreamingResponse(self) @@ -119,7 +119,7 @@ def with_raw_response(self) -> AsyncStepsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncStepsResourceWithRawResponse(self) @@ -128,7 +128,7 @@ def with_streaming_response(self) -> AsyncStepsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncStepsResourceWithStreamingResponse(self) diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index ab9d85d..1faa81f 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -54,7 +54,7 @@ def with_raw_response(self) -> WorkflowsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return WorkflowsResourceWithRawResponse(self) @@ -63,7 +63,7 @@ def with_streaming_response(self) -> WorkflowsResourceWithStreamingResponse: """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return WorkflowsResourceWithStreamingResponse(self) @@ -428,7 +428,7 @@ def with_raw_response(self) -> AsyncWorkflowsResourceWithRawResponse: 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/knock-mapi-python#accessing-raw-response-data-eg-headers + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers """ return AsyncWorkflowsResourceWithRawResponse(self) @@ -437,7 +437,7 @@ def with_streaming_response(self) -> AsyncWorkflowsResourceWithStreamingResponse """ An alternative to `.with_raw_response` that doesn't eagerly read the response body. - For more information, see https://www.github.com/stainless-sdks/knock-mapi-python#with_streaming_response + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response """ return AsyncWorkflowsResourceWithStreamingResponse(self) From 7947d31302f3e0e3d43ba21e84aaf0a06e541f5b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 May 2025 04:42:51 +0000 Subject: [PATCH 002/101] chore(internal): avoid errors for isinstance checks on proxies --- src/knock_mapi/_utils/_proxy.py | 5 ++++- tests/test_utils/test_proxy.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/knock_mapi/_utils/_proxy.py b/src/knock_mapi/_utils/_proxy.py index ffd883e..0f239a3 100644 --- a/src/knock_mapi/_utils/_proxy.py +++ b/src/knock_mapi/_utils/_proxy.py @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index 9b4a45a..284f8b8 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -21,3 +21,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy) From 1cb0a5c285e1965ae02d91c89d1e58b5cf4bf7c9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 10 May 2025 03:57:41 +0000 Subject: [PATCH 003/101] fix(package): support direct resource imports --- src/knock_mapi/__init__.py | 5 +++++ src/knock_mapi/_utils/_resources_proxy.py | 24 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/knock_mapi/_utils/_resources_proxy.py diff --git a/src/knock_mapi/__init__.py b/src/knock_mapi/__init__.py index ea3e26c..b070524 100644 --- a/src/knock_mapi/__init__.py +++ b/src/knock_mapi/__init__.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import typing as _t + from . import types from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path @@ -78,6 +80,9 @@ "DefaultAsyncHttpxClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + _setup_logging() # Update the __module__ attribute for exported symbols so that diff --git a/src/knock_mapi/_utils/_resources_proxy.py b/src/knock_mapi/_utils/_resources_proxy.py new file mode 100644 index 0000000..8918f2e --- /dev/null +++ b/src/knock_mapi/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `knock_mapi.resources` module. + + This is used so that we can lazily import `knock_mapi.resources` only when + needed *and* so that users can just import `knock_mapi` and reference `knock_mapi.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("knock_mapi.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() From 526aeecc6c6975207ad58e88eed5adc15c04e27d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 05:28:00 +0000 Subject: [PATCH 004/101] chore(ci): upload sdks to package manager --- .github/workflows/ci.yml | 24 ++++++++++++++++++++++++ scripts/utils/upload-artifact.sh | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100755 scripts/utils/upload-artifact.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caa50bc..bc14726 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,30 @@ jobs: - name: Run lints run: ./scripts/lint + upload: + if: github.repository == 'stainless-sdks/knock-mapi-python' + timeout-minutes: 10 + name: upload + permissions: + contents: read + id-token: write + runs-on: depot-ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Get GitHub OIDC Token + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + test: timeout-minutes: 10 name: test diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 0000000..27b3591 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -exuo pipefail + +RESPONSE=$(curl -X POST "$URL" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ + -H "Content-Type: application/gzip" \ + --data-binary @- "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi From 136b83e5dcad2f71b08f48b536dd0e9f463f5a8e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 May 2025 04:09:43 +0000 Subject: [PATCH 005/101] chore(ci): fix installation instructions --- scripts/utils/upload-artifact.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 27b3591..fa79708 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From 8ffd5af66c23e840f4f7be4892b092c862fad587 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 May 2025 02:59:00 +0000 Subject: [PATCH 006/101] chore(internal): codegen related update --- scripts/utils/upload-artifact.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index fa79708..25472fa 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install --pre 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From b623da9bf447b1df85c9cc200996aa24685de3de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 02:37:41 +0000 Subject: [PATCH 007/101] chore(docs): grammar improvements --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 5936da4..b455718 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,11 +16,11 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Knock Mgmt please follow the respective company's security reporting guidelines. +or products provided by Knock Mgmt, please follow the respective company's security reporting guidelines. ### Knock Mgmt Terms and Policies -Please contact support@knock.app for any questions or concerns regarding security of our services. +Please contact support@knock.app for any questions or concerns regarding the security of our services. --- From 2ce93ae3634eeaf460ddccd643bc4b20d02f5cdc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 02:32:24 +0000 Subject: [PATCH 008/101] chore(docs): remove reference to rye shell --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 848b4db..91bd2b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,7 @@ $ rye sync --all-features You can then run scripts using `rye run python script.py` or by activating the virtual environment: ```sh -$ rye shell -# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work +# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work $ source .venv/bin/activate # now you can omit the `rye run` prefix From 5079fb92ff59e10bc72b2af1489724f56fcd3911 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 03:47:12 +0000 Subject: [PATCH 009/101] feat(client): add follow_redirects request option --- src/knock_mapi/_base_client.py | 6 ++++ src/knock_mapi/_models.py | 2 ++ src/knock_mapi/_types.py | 2 ++ tests/test_client.py | 56 +++++++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index 426b03d..ffa5b05 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -960,6 +960,9 @@ def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None @@ -1460,6 +1463,9 @@ async def request( if self.custom_auth is not None: kwargs["auth"] = self.custom_auth + if options.follow_redirects is not None: + kwargs["follow_redirects"] = options.follow_redirects + log.debug("Sending HTTP Request: %s %s", request.method, request.url) response = None diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 798956f..4f21498 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False): idempotency_key: str json_data: Body extra_json: AnyMapping + follow_redirects: bool @final @@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel): files: Union[HttpxRequestFiles, None] = None idempotency_key: Union[str, None] = None post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() + follow_redirects: Union[bool, None] = None # It should be noted that we cannot use `json` here as that would override # a BaseModel method in an incompatible fashion. diff --git a/src/knock_mapi/_types.py b/src/knock_mapi/_types.py index d27367c..f38ff3f 100644 --- a/src/knock_mapi/_types.py +++ b/src/knock_mapi/_types.py @@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False): params: Query extra_json: AnyMapping idempotency_key: str + follow_redirects: bool # Sentinel class used until PEP 0661 is accepted @@ -215,3 +216,4 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth + follow_redirects: bool diff --git a/tests/test_client.py b/tests/test_client.py index 2e1a8fd..e025cfc 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -24,7 +24,7 @@ from knock_mapi import KnockMgmt, AsyncKnockMgmt, APIResponseValidationError from knock_mapi._types import Omit from knock_mapi._models import BaseModel, FinalRequestOptions -from knock_mapi._exceptions import KnockMgmtError, APIResponseValidationError +from knock_mapi._exceptions import APIStatusError, KnockMgmtError, APIResponseValidationError from knock_mapi._base_client import ( DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, @@ -821,6 +821,33 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" + class TestAsyncKnockMgmt: client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) @@ -1648,3 +1675,30 @@ async def test_main() -> None: raise AssertionError("calling get_platform using asyncify resulted in a hung process") time.sleep(0.1) + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + # Test that the default follow_redirects=True allows following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) + + response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + @pytest.mark.respx(base_url=base_url) + async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + # Test that follow_redirects=False prevents following redirects + respx_mock.post("/redirect").mock( + return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) + ) + + with pytest.raises(APIStatusError) as exc_info: + await self.client.post( + "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response + ) + + assert exc_info.value.response.status_code == 302 + assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" From c4adff61602002577b5240580dc941028e3eb17f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:17:25 +0000 Subject: [PATCH 010/101] chore(tests): run tests in parallel --- pyproject.toml | 3 ++- requirements-dev.lock | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ca332b6..05161ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ dev-dependencies = [ "importlib-metadata>=6.7.0", "rich>=13.7.1", "nest_asyncio==1.6.0", + "pytest-xdist>=3.6.1", ] [tool.rye.scripts] @@ -125,7 +126,7 @@ replacement = '[\1](https://github.com/knocklabs/knock-mgmt-python/tree/main/\g< [tool.pytest.ini_options] testpaths = ["tests"] -addopts = "--tb=short" +addopts = "--tb=short -n auto" xfail_strict = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" diff --git a/requirements-dev.lock b/requirements-dev.lock index 2840953..751a44d 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -30,6 +30,8 @@ distro==1.8.0 exceptiongroup==1.2.2 # via anyio # via pytest +execnet==2.1.1 + # via pytest-xdist filelock==3.12.4 # via virtualenv h11==0.14.0 @@ -72,7 +74,9 @@ pygments==2.18.0 pyright==1.1.399 pytest==8.3.3 # via pytest-asyncio + # via pytest-xdist pytest-asyncio==0.24.0 +pytest-xdist==3.7.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 From 8d0c46bca0475d69f0100ced4db27560b0f18b54 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Jun 2025 02:41:52 +0000 Subject: [PATCH 011/101] fix(client): correctly parse binary response | stream --- src/knock_mapi/_base_client.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index ffa5b05..f95a219 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -1071,7 +1071,14 @@ def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, APIResponse): raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") @@ -1574,7 +1581,14 @@ async def _process_response( ) -> ResponseT: origin = get_origin(cast_to) or cast_to - if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse): + if ( + inspect.isclass(origin) + and issubclass(origin, BaseAPIResponse) + # we only want to actually return the custom BaseAPIResponse class if we're + # returning the raw response, or if we're not streaming SSE, as if we're streaming + # SSE then `cast_to` doesn't actively reflect the type we need to parse into + and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) + ): if not issubclass(origin, AsyncAPIResponse): raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") From 69f66beff3e47d5247968cecb2de84a0d7ec658d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 02:49:27 +0000 Subject: [PATCH 012/101] chore(tests): add tests for httpx client instantiation & proxies --- tests/test_client.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index e025cfc..a72036a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -29,6 +29,8 @@ DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, + DefaultHttpxClient, + DefaultAsyncHttpxClient, make_request_options, ) @@ -821,6 +823,28 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" + def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects @@ -1676,6 +1700,28 @@ async def test_main() -> None: time.sleep(0.1) + async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: + # Test that the proxy environment variables are set correctly + monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + + client = DefaultAsyncHttpxClient() + + mounts = tuple(client._mounts.items()) + assert len(mounts) == 1 + assert mounts[0][0].pattern == "https://" + + @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") + async def test_default_client_creation(self) -> None: + # Ensure that the client can be initialized without any exceptions + DefaultAsyncHttpxClient( + verify=True, + cert=None, + trust_env=True, + http1=True, + http2=False, + limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), + ) + @pytest.mark.respx(base_url=base_url) async def test_follow_redirects(self, respx_mock: MockRouter) -> None: # Test that the default follow_redirects=True allows following redirects From 2cbbdbcebfd41c2d85f00a6bf88b5fdf9f710c9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:18:35 +0000 Subject: [PATCH 013/101] chore(internal): update conftest.py --- tests/conftest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index c8f563b..9d1bfb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + from __future__ import annotations import os From 43b4165055db298bf6625629b1eb38d64ab821ff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 06:49:51 +0000 Subject: [PATCH 014/101] chore(ci): enable for pull requests --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc14726..7aaa2c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: From bb17cec1d07a1b218882dcaff2b8019122efa156 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:21:23 +0000 Subject: [PATCH 015/101] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd53cd0..adadc2b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Knock Mgmt Python API library -[![PyPI version](https://img.shields.io/pypi/v/knock_mapi.svg)](https://pypi.org/project/knock_mapi/) +[![PyPI version]()](https://pypi.org/project/knock_mapi/) The Knock Mgmt Python library provides convenient access to the Knock Mgmt REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From f85ddbee1539127553bd259d61db9a155de2268e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Jun 2025 02:59:26 +0000 Subject: [PATCH 016/101] docs(client): fix httpx.Timeout documentation reference --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index adadc2b..5fabe3c 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,7 @@ client.with_options(max_retries=5).workflows.list( ### Timeouts By default requests time out after 1 minute. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object: +which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python from knock_mapi import KnockMgmt From aac5b4663dfda3909e1133acad7fbbf843cdc726 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 03:36:38 +0000 Subject: [PATCH 017/101] chore: change publish docs url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fabe3c..80804b7 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ pip install git+ssh://git@github.com/knocklabs/knock-mgmt-python.git ``` > [!NOTE] -> Once this package is [published to PyPI](https://app.stainless.com/docs/guides/publish), this will become: `pip install --pre knock_mapi` +> Once this package is [published to PyPI](https://www.stainless.com/docs/guides/publish), this will become: `pip install --pre knock_mapi` ## Usage From 0a040e281f0077e1707d4225654510a42a3a2fb0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 04:32:56 +0000 Subject: [PATCH 018/101] feat(client): add support for aiohttp --- README.md | 36 +++++++++++++++++++ pyproject.toml | 2 ++ requirements-dev.lock | 27 ++++++++++++++ requirements.lock | 27 ++++++++++++++ src/knock_mapi/__init__.py | 3 +- src/knock_mapi/_base_client.py | 22 ++++++++++++ tests/api_resources/test_api_keys.py | 4 ++- tests/api_resources/test_auth.py | 4 ++- tests/api_resources/test_channel_groups.py | 4 ++- tests/api_resources/test_channels.py | 4 ++- tests/api_resources/test_commits.py | 4 ++- tests/api_resources/test_email_layouts.py | 4 ++- tests/api_resources/test_environments.py | 4 ++- tests/api_resources/test_message_types.py | 4 ++- tests/api_resources/test_partials.py | 4 ++- tests/api_resources/test_translations.py | 4 ++- tests/api_resources/test_variables.py | 4 ++- tests/api_resources/test_workflows.py | 4 ++- tests/api_resources/workflows/test_steps.py | 4 ++- tests/conftest.py | 39 ++++++++++++++++++--- 20 files changed, 189 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 80804b7..93c3ec3 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,42 @@ asyncio.run(main()) Functionality between the synchronous and asynchronous clients is otherwise identical. +### With aiohttp + +By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. + +You can enable this by installing `aiohttp`: + +```sh +# install from the production repo +pip install 'knock_mapi[aiohttp] @ git+ssh://git@github.com/knocklabs/knock-mgmt-python.git' +``` + +Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: + +```python +import os +import asyncio +from knock_mapi import DefaultAioHttpClient +from knock_mapi import AsyncKnockMgmt + + +async def main() -> None: + async with AsyncKnockMgmt( + service_token=os.environ.get( + "KNOCK_SERVICE_TOKEN" + ), # This is the default and can be omitted + http_client=DefaultAioHttpClient(), + ) as client: + page = await client.workflows.list( + environment="development", + ) + print(page.entries) + + +asyncio.run(main()) +``` + ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: diff --git a/pyproject.toml b/pyproject.toml index 05161ce..688540e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,8 @@ classifiers = [ Homepage = "https://github.com/knocklabs/knock-mgmt-python" Repository = "https://github.com/knocklabs/knock-mgmt-python" +[project.optional-dependencies] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] [tool.rye] managed = true diff --git a/requirements-dev.lock b/requirements-dev.lock index 751a44d..693543e 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -10,6 +10,13 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via httpx-aiohttp + # via knock-mapi +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 @@ -17,6 +24,10 @@ anyio==4.4.0 # via knock-mapi argcomplete==3.1.2 # via nox +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -34,16 +45,23 @@ execnet==2.1.1 # via pytest-xdist filelock==3.12.4 # via virtualenv +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp # via knock-mapi # via respx +httpx-aiohttp==0.1.6 + # via knock-mapi idna==3.4 # via anyio # via httpx + # via yarl importlib-metadata==7.0.0 iniconfig==2.0.0 # via pytest @@ -51,6 +69,9 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py +multidict==6.4.4 + # via aiohttp + # via yarl mypy==1.14.1 mypy-extensions==1.0.0 # via mypy @@ -65,6 +86,9 @@ platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 # via pytest +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via knock-mapi pydantic-core==2.27.1 @@ -98,11 +122,14 @@ tomli==2.0.2 typing-extensions==4.12.2 # via anyio # via knock-mapi + # via multidict # via mypy # via pydantic # via pydantic-core # via pyright virtualenv==20.24.5 # via nox +yarl==1.20.0 + # via aiohttp zipp==3.17.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 4028537..6da1848 100644 --- a/requirements.lock +++ b/requirements.lock @@ -10,11 +10,22 @@ # universal: false -e file:. +aiohappyeyeballs==2.6.1 + # via aiohttp +aiohttp==3.12.8 + # via httpx-aiohttp + # via knock-mapi +aiosignal==1.3.2 + # via aiohttp annotated-types==0.6.0 # via pydantic anyio==4.4.0 # via httpx # via knock-mapi +async-timeout==5.0.1 + # via aiohttp +attrs==25.3.0 + # via aiohttp certifi==2023.7.22 # via httpcore # via httpx @@ -22,15 +33,28 @@ distro==1.8.0 # via knock-mapi exceptiongroup==1.2.2 # via anyio +frozenlist==1.6.2 + # via aiohttp + # via aiosignal h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx httpx==0.28.1 + # via httpx-aiohttp + # via knock-mapi +httpx-aiohttp==0.1.6 # via knock-mapi idna==3.4 # via anyio # via httpx + # via yarl +multidict==6.4.4 + # via aiohttp + # via yarl +propcache==0.3.1 + # via aiohttp + # via yarl pydantic==2.10.3 # via knock-mapi pydantic-core==2.27.1 @@ -41,5 +65,8 @@ sniffio==1.3.0 typing-extensions==4.12.2 # via anyio # via knock-mapi + # via multidict # via pydantic # via pydantic-core +yarl==1.20.0 + # via aiohttp diff --git a/src/knock_mapi/__init__.py b/src/knock_mapi/__init__.py index b070524..bc4d532 100644 --- a/src/knock_mapi/__init__.py +++ b/src/knock_mapi/__init__.py @@ -36,7 +36,7 @@ UnprocessableEntityError, APIResponseValidationError, ) -from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient +from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient from ._utils._logs import setup_logging as _setup_logging __all__ = [ @@ -78,6 +78,7 @@ "DEFAULT_CONNECTION_LIMITS", "DefaultHttpxClient", "DefaultAsyncHttpxClient", + "DefaultAioHttpClient", ] if not _t.TYPE_CHECKING: diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index f95a219..3534752 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -1289,6 +1289,24 @@ def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) +try: + import httpx_aiohttp +except ImportError: + + class _DefaultAioHttpClient(httpx.AsyncClient): + def __init__(self, **_kwargs: Any) -> None: + raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") +else: + + class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore + def __init__(self, **kwargs: Any) -> None: + kwargs.setdefault("timeout", DEFAULT_TIMEOUT) + kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) + kwargs.setdefault("follow_redirects", True) + + super().__init__(**kwargs) + + if TYPE_CHECKING: DefaultAsyncHttpxClient = httpx.AsyncClient """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK @@ -1297,8 +1315,12 @@ def __init__(self, **kwargs: Any) -> None: This is useful because overriding the `http_client` with your own instance of `httpx.AsyncClient` will result in httpx's defaults being used, not ours. """ + + DefaultAioHttpClient = httpx.AsyncClient + """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" else: DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient + DefaultAioHttpClient = _DefaultAioHttpClient class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): diff --git a/tests/api_resources/test_api_keys.py b/tests/api_resources/test_api_keys.py index bf8cf39..08011b3 100644 --- a/tests/api_resources/test_api_keys.py +++ b/tests/api_resources/test_api_keys.py @@ -59,7 +59,9 @@ def test_streaming_response_exchange(self, client: KnockMgmt) -> None: class TestAsyncAPIKeys: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py index 318b4c2..f10cb0d 100644 --- a/tests/api_resources/test_auth.py +++ b/tests/api_resources/test_auth.py @@ -53,7 +53,9 @@ def test_streaming_response_verify(self, client: KnockMgmt) -> None: class TestAsyncAuth: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_channel_groups.py b/tests/api_resources/test_channel_groups.py index 7a32416..1f344c5 100644 --- a/tests/api_resources/test_channel_groups.py +++ b/tests/api_resources/test_channel_groups.py @@ -66,7 +66,9 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: class TestAsyncChannelGroups: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_channels.py b/tests/api_resources/test_channels.py index 3c22778..a8ece50 100644 --- a/tests/api_resources/test_channels.py +++ b/tests/api_resources/test_channels.py @@ -66,7 +66,9 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: class TestAsyncChannels: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 368fb3a..8649cb3 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -270,7 +270,9 @@ def test_path_params_promote_one(self, client: KnockMgmt) -> None: class TestAsyncCommits: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_email_layouts.py b/tests/api_resources/test_email_layouts.py index f9c92b1..3b25c70 100644 --- a/tests/api_resources/test_email_layouts.py +++ b/tests/api_resources/test_email_layouts.py @@ -341,7 +341,9 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: class TestAsyncEmailLayouts: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_environments.py b/tests/api_resources/test_environments.py index 560f10b..cd00196 100644 --- a/tests/api_resources/test_environments.py +++ b/tests/api_resources/test_environments.py @@ -116,7 +116,9 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: class TestAsyncEnvironments: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_message_types.py b/tests/api_resources/test_message_types.py index 70990d1..df8b405 100644 --- a/tests/api_resources/test_message_types.py +++ b/tests/api_resources/test_message_types.py @@ -373,7 +373,9 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: class TestAsyncMessageTypes: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_partials.py b/tests/api_resources/test_partials.py index c8c2c0e..44a498d 100644 --- a/tests/api_resources/test_partials.py +++ b/tests/api_resources/test_partials.py @@ -335,7 +335,9 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: class TestAsyncPartials: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_translations.py b/tests/api_resources/test_translations.py index 3320481..b68c396 100644 --- a/tests/api_resources/test_translations.py +++ b/tests/api_resources/test_translations.py @@ -316,7 +316,9 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: class TestAsyncTranslations: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_variables.py b/tests/api_resources/test_variables.py index c3eeb56..09ec4ea 100644 --- a/tests/api_resources/test_variables.py +++ b/tests/api_resources/test_variables.py @@ -73,7 +73,9 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: class TestAsyncVariables: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 497a224..7da3348 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -640,7 +640,9 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: class TestAsyncWorkflows: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/api_resources/workflows/test_steps.py b/tests/api_resources/workflows/test_steps.py index aede731..8dc1c92 100644 --- a/tests/api_resources/workflows/test_steps.py +++ b/tests/api_resources/workflows/test_steps.py @@ -105,7 +105,9 @@ def test_path_params_preview_template(self, client: KnockMgmt) -> None: class TestAsyncSteps: - parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) @pytest.mark.skip( reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" diff --git a/tests/conftest.py b/tests/conftest.py index 9d1bfb4..6df9560 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,10 +6,12 @@ import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator +import httpx import pytest from pytest_asyncio import is_async_test -from knock_mapi import KnockMgmt, AsyncKnockMgmt +from knock_mapi import KnockMgmt, AsyncKnockMgmt, DefaultAioHttpClient +from knock_mapi._utils import is_dict if TYPE_CHECKING: from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] @@ -27,6 +29,19 @@ def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: for async_test in pytest_asyncio_tests: async_test.add_marker(session_scope_marker, append=False) + # We skip tests that use both the aiohttp client and respx_mock as respx_mock + # doesn't support custom transports. + for item in items: + if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: + continue + + if not hasattr(item, "callspec"): + continue + + async_client_param = item.callspec.params.get("async_client") + if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": + item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -45,11 +60,25 @@ def client(request: FixtureRequest) -> Iterator[KnockMgmt]: @pytest.fixture(scope="session") async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncKnockMgmt]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") + param = getattr(request, "param", True) + + # defaults + strict = True + http_client: None | httpx.AsyncClient = None + + if isinstance(param, bool): + strict = param + elif is_dict(param): + strict = param.get("strict", True) + assert isinstance(strict, bool) + + http_client_type = param.get("http_client", "httpx") + if http_client_type == "aiohttp": + http_client = DefaultAioHttpClient() + else: + raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") async with AsyncKnockMgmt( - base_url=base_url, service_token=service_token, _strict_response_validation=strict + base_url=base_url, service_token=service_token, _strict_response_validation=strict, http_client=http_client ) as client: yield client From 0d15d2b669b62c4927bd71c31e92cad6a5be78fd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:28:00 +0000 Subject: [PATCH 019/101] chore(tests): skip some failing tests on the latest python versions --- tests/test_client.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index a72036a..de00cd2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -189,6 +189,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") @@ -1014,6 +1015,7 @@ def test_copy_signature(self) -> None: copy_param = copy_signature.parameters.get(name) assert copy_param is not None, f"copy() signature is missing the {name} param" + @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") def test_copy_build_request(self) -> None: options = FinalRequestOptions(method="get", url="/foo") From 7021893dab2b10080eb01e6a5e665e421ce30e6f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 02:42:46 +0000 Subject: [PATCH 020/101] =?UTF-8?q?fix(ci):=20release-doctor=20=E2=80=94?= =?UTF-8?q?=20report=20correct=20token=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/check-release-environment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check-release-environment b/bin/check-release-environment index 40ee32e..b845b0f 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The KNOCK_MGMT_PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") + 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[@]} From f04705e5d5f746990f96f2f950972a8733ff672d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 08:52:37 +0000 Subject: [PATCH 021/101] chore(ci): only run for pushes and fork pull requests --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7aaa2c7..5c8a061 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/knock-mapi-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -42,6 +43,7 @@ jobs: contents: read id-token: write runs-on: depot-ubuntu-24.04 + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -62,6 +64,7 @@ jobs: timeout-minutes: 10 name: test runs-on: ${{ github.repository == 'stainless-sdks/knock-mapi-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From a96a2bbd60bd1b9d6b93dd5f83ba658f4934eeae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 30 Jun 2025 02:37:57 +0000 Subject: [PATCH 022/101] fix(ci): correct conditional --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c8a061..2996b00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,13 @@ jobs: run: ./scripts/lint upload: - if: github.repository == 'stainless-sdks/knock-mapi-python' + if: github.repository == 'stainless-sdks/knock-mapi-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 name: upload permissions: contents: read id-token: write runs-on: depot-ubuntu-24.04 - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From 649edef425c6fb6bb9e227dd830d324e88985043 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 19:27:20 +0000 Subject: [PATCH 023/101] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8eebb3f..5eaec22 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 35 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-305e73d67d2964dc9148b0f091d040e1d2899960af5815ecac64089110085804.yml -openapi_spec_hash: 90b9e75af20d6209e1a294d7227120fc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml +openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 config_hash: 24265f2774d9e93e37cccc0726c8555f From 06bf7febdcdfec47d98cc82a9419e90c375846eb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 05:11:15 +0000 Subject: [PATCH 024/101] chore(ci): change upload type --- .github/workflows/ci.yml | 18 ++++++++++++++++-- scripts/utils/upload-artifact.sh | 12 +++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2996b00..081bf0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,10 @@ jobs: - name: Run lints run: ./scripts/lint - upload: + build: if: github.repository == 'stainless-sdks/knock-mapi-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) timeout-minutes: 10 - name: upload + name: build permissions: contents: read id-token: write @@ -46,6 +46,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install Rye + run: | + curl -sSf https://rye.astral.sh/get | bash + echo "$HOME/.rye/shims" >> $GITHUB_PATH + env: + RYE_VERSION: '0.44.0' + RYE_INSTALL_OPTION: '--yes' + + - name: Install dependencies + run: rye sync --all-features + + - name: Run build + run: rye build + - name: Get GitHub OIDC Token id: github-oidc uses: actions/github-script@v6 diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 25472fa..22e9829 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash set -exuo pipefail -RESPONSE=$(curl -X POST "$URL" \ +FILENAME=$(basename dist/*.whl) + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ -H "Authorization: Bearer $AUTH" \ -H "Content-Type: application/json") @@ -12,13 +14,13 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz . | curl -v -X PUT \ - -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: binary/octet-stream" \ + --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install --pre 'https://pkg.stainless.com/s/knock-mapi-python/$SHA'\033[0m" + echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/knock-mapi-python/$SHA/$FILENAME'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 From f338ae03f8f09b01885dafe4c28c8df49b856434 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:09:05 +0000 Subject: [PATCH 025/101] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5eaec22..6916b4b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 35 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml -openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-8914c38095687c00f8eae951cd552322fc67fde889e91073a1902e74880eddd0.yml +openapi_spec_hash: 9e4969211d88407f1f9e802eaa395a6a config_hash: 24265f2774d9e93e37cccc0726c8555f From 6deba0f2e192260d524c7ac454cbcbed8458b745 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:21:51 +0000 Subject: [PATCH 026/101] feat(api): manual updates --- .stats.yml | 8 +- api.md | 22 + src/knock_mapi/_client.py | 9 + src/knock_mapi/resources/__init__.py | 14 + src/knock_mapi/resources/guides.py | 853 +++++++++++++ src/knock_mapi/types/__init__.py | 11 + src/knock_mapi/types/guide.py | 86 ++ src/knock_mapi/types/guide_activate_params.py | 41 + .../types/guide_activate_response.py | 14 + src/knock_mapi/types/guide_list_params.py | 31 + src/knock_mapi/types/guide_retrieve_params.py | 22 + src/knock_mapi/types/guide_step.py | 34 + src/knock_mapi/types/guide_step_param.py | 34 + src/knock_mapi/types/guide_upsert_params.py | 80 ++ src/knock_mapi/types/guide_upsert_response.py | 14 + src/knock_mapi/types/guide_validate_params.py | 71 ++ .../types/guide_validate_response.py | 14 + src/knock_mapi/types/workflow_run_params.py | 16 +- .../workflows/step_preview_template_params.py | 16 +- tests/api_resources/test_guides.py | 1123 +++++++++++++++++ 20 files changed, 2499 insertions(+), 14 deletions(-) create mode 100644 src/knock_mapi/resources/guides.py create mode 100644 src/knock_mapi/types/guide.py create mode 100644 src/knock_mapi/types/guide_activate_params.py create mode 100644 src/knock_mapi/types/guide_activate_response.py create mode 100644 src/knock_mapi/types/guide_list_params.py create mode 100644 src/knock_mapi/types/guide_retrieve_params.py create mode 100644 src/knock_mapi/types/guide_step.py create mode 100644 src/knock_mapi/types/guide_step_param.py create mode 100644 src/knock_mapi/types/guide_upsert_params.py create mode 100644 src/knock_mapi/types/guide_upsert_response.py create mode 100644 src/knock_mapi/types/guide_validate_params.py create mode 100644 src/knock_mapi/types/guide_validate_response.py create mode 100644 tests/api_resources/test_guides.py diff --git a/.stats.yml b/.stats.yml index 6916b4b..34f6cfa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 35 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-8914c38095687c00f8eae951cd552322fc67fde889e91073a1902e74880eddd0.yml -openapi_spec_hash: 9e4969211d88407f1f9e802eaa395a6a -config_hash: 24265f2774d9e93e37cccc0726c8555f +configured_endpoints: 40 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-604e7da30835c75d1659200bff074f2551f805ca2a0a83265ee422a7ac61b919.yml +openapi_spec_hash: f15fb2c57a561ece4231ea3052d6db27 +config_hash: acee12c9c8095ab1f2abc4972c70821a diff --git a/api.md b/api.md index 8151c12..f48b15f 100644 --- a/api.md +++ b/api.md @@ -238,3 +238,25 @@ from knock_mapi.types import Variable Methods: - client.variables.list(\*\*params) -> SyncEntriesCursor[Variable] + +# Guides + +Types: + +```python +from knock_mapi.types import ( + Guide, + GuideStep, + GuideActivateResponse, + GuideUpsertResponse, + GuideValidateResponse, +) +``` + +Methods: + +- client.guides.retrieve(guide_key, \*\*params) -> Guide +- client.guides.list(\*\*params) -> SyncEntriesCursor[Guide] +- client.guides.activate(guide_key, \*\*params) -> GuideActivateResponse +- client.guides.upsert(guide_key, \*\*params) -> GuideUpsertResponse +- client.guides.validate(guide_key, \*\*params) -> GuideValidateResponse diff --git a/src/knock_mapi/_client.py b/src/knock_mapi/_client.py index fb65def..937aeab 100644 --- a/src/knock_mapi/_client.py +++ b/src/knock_mapi/_client.py @@ -23,6 +23,7 @@ from ._version import __version__ from .resources import ( auth, + guides, commits, api_keys, channels, @@ -68,6 +69,7 @@ class KnockMgmt(SyncAPIClient): channels: channels.ChannelsResource environments: environments.EnvironmentsResource variables: variables.VariablesResource + guides: guides.GuidesResource with_raw_response: KnockMgmtWithRawResponse with_streaming_response: KnockMgmtWithStreamedResponse @@ -137,6 +139,7 @@ def __init__( self.channels = channels.ChannelsResource(self) self.environments = environments.EnvironmentsResource(self) self.variables = variables.VariablesResource(self) + self.guides = guides.GuidesResource(self) self.with_raw_response = KnockMgmtWithRawResponse(self) self.with_streaming_response = KnockMgmtWithStreamedResponse(self) @@ -258,6 +261,7 @@ class AsyncKnockMgmt(AsyncAPIClient): channels: channels.AsyncChannelsResource environments: environments.AsyncEnvironmentsResource variables: variables.AsyncVariablesResource + guides: guides.AsyncGuidesResource with_raw_response: AsyncKnockMgmtWithRawResponse with_streaming_response: AsyncKnockMgmtWithStreamedResponse @@ -327,6 +331,7 @@ def __init__( self.channels = channels.AsyncChannelsResource(self) self.environments = environments.AsyncEnvironmentsResource(self) self.variables = variables.AsyncVariablesResource(self) + self.guides = guides.AsyncGuidesResource(self) self.with_raw_response = AsyncKnockMgmtWithRawResponse(self) self.with_streaming_response = AsyncKnockMgmtWithStreamedResponse(self) @@ -449,6 +454,7 @@ def __init__(self, client: KnockMgmt) -> None: self.channels = channels.ChannelsResourceWithRawResponse(client.channels) self.environments = environments.EnvironmentsResourceWithRawResponse(client.environments) self.variables = variables.VariablesResourceWithRawResponse(client.variables) + self.guides = guides.GuidesResourceWithRawResponse(client.guides) class AsyncKnockMgmtWithRawResponse: @@ -465,6 +471,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.channels = channels.AsyncChannelsResourceWithRawResponse(client.channels) self.environments = environments.AsyncEnvironmentsResourceWithRawResponse(client.environments) self.variables = variables.AsyncVariablesResourceWithRawResponse(client.variables) + self.guides = guides.AsyncGuidesResourceWithRawResponse(client.guides) class KnockMgmtWithStreamedResponse: @@ -481,6 +488,7 @@ def __init__(self, client: KnockMgmt) -> None: self.channels = channels.ChannelsResourceWithStreamingResponse(client.channels) self.environments = environments.EnvironmentsResourceWithStreamingResponse(client.environments) self.variables = variables.VariablesResourceWithStreamingResponse(client.variables) + self.guides = guides.GuidesResourceWithStreamingResponse(client.guides) class AsyncKnockMgmtWithStreamedResponse: @@ -497,6 +505,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.channels = channels.AsyncChannelsResourceWithStreamingResponse(client.channels) self.environments = environments.AsyncEnvironmentsResourceWithStreamingResponse(client.environments) self.variables = variables.AsyncVariablesResourceWithStreamingResponse(client.variables) + self.guides = guides.AsyncGuidesResourceWithStreamingResponse(client.guides) Client = KnockMgmt diff --git a/src/knock_mapi/resources/__init__.py b/src/knock_mapi/resources/__init__.py index 921529c..e1e8da3 100644 --- a/src/knock_mapi/resources/__init__.py +++ b/src/knock_mapi/resources/__init__.py @@ -8,6 +8,14 @@ AuthResourceWithStreamingResponse, AsyncAuthResourceWithStreamingResponse, ) +from .guides import ( + GuidesResource, + AsyncGuidesResource, + GuidesResourceWithRawResponse, + AsyncGuidesResourceWithRawResponse, + GuidesResourceWithStreamingResponse, + AsyncGuidesResourceWithStreamingResponse, +) from .commits import ( CommitsResource, AsyncCommitsResource, @@ -170,4 +178,10 @@ "AsyncVariablesResourceWithRawResponse", "VariablesResourceWithStreamingResponse", "AsyncVariablesResourceWithStreamingResponse", + "GuidesResource", + "AsyncGuidesResource", + "GuidesResourceWithRawResponse", + "AsyncGuidesResourceWithRawResponse", + "GuidesResourceWithStreamingResponse", + "AsyncGuidesResourceWithStreamingResponse", ] diff --git a/src/knock_mapi/resources/guides.py b/src/knock_mapi/resources/guides.py new file mode 100644 index 0000000..ee5b5d8 --- /dev/null +++ b/src/knock_mapi/resources/guides.py @@ -0,0 +1,853 @@ +# 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 overload + +import httpx + +from ..types import ( + guide_list_params, + guide_upsert_params, + guide_activate_params, + guide_retrieve_params, + guide_validate_params, +) +from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._utils import required_args, 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 SyncEntriesCursor, AsyncEntriesCursor +from ..types.guide import Guide +from .._base_client import AsyncPaginator, make_request_options +from ..types.guide_upsert_response import GuideUpsertResponse +from ..types.guide_activate_response import GuideActivateResponse +from ..types.guide_validate_response import GuideValidateResponse + +__all__ = ["GuidesResource", "AsyncGuidesResource"] + + +class GuidesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> GuidesResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return GuidesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> GuidesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return GuidesResourceWithStreamingResponse(self) + + def retrieve( + self, + guide_key: str, + *, + environment: str, + annotate: bool | NotGiven = NOT_GIVEN, + hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Guide: + """ + Get a guide by its key. + + Args: + environment: The environment slug. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return self._get( + f"/v1/guides/{guide_key}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "annotate": annotate, + "hide_uncommitted_changes": hide_uncommitted_changes, + }, + guide_retrieve_params.GuideRetrieveParams, + ), + ), + cast_to=Guide, + ) + + def list( + self, + *, + environment: str, + after: str | NotGiven = NOT_GIVEN, + annotate: bool | NotGiven = NOT_GIVEN, + before: str | NotGiven = NOT_GIVEN, + hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> SyncEntriesCursor[Guide]: + """ + Returns a paginated list of guides available in a given environment. + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + before: The cursor to fetch entries before. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/guides", + page=SyncEntriesCursor[Guide], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "annotate": annotate, + "before": before, + "hide_uncommitted_changes": hide_uncommitted_changes, + "limit": limit, + }, + guide_list_params.GuideListParams, + ), + ), + model=Guide, + ) + + @overload + def activate( + self, + guide_key: str, + *, + environment: str, + status: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + """Activates (or deactivates) a guide in a given environment. + + You can either set + the active status immediately or schedule it. + + Note: This immediately enables or disables a guide in a given environment + without needing to go through environment promotion. + + Args: + environment: The environment slug. + + status: Whether to activate or deactivate the guide. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + def activate( + self, + guide_key: str, + *, + environment: str, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + until: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + """Activates (or deactivates) a guide in a given environment. + + You can either set + the active status immediately or schedule it. + + Note: This immediately enables or disables a guide in a given environment + without needing to go through environment promotion. + + Args: + environment: The environment slug. + + from_: When to activate the guide. If provided, the guide will be scheduled to activate + at this time. Must be in ISO 8601 UTC format. + + until: When to deactivate the guide. If provided, the guide will be scheduled to + deactivate at this time. Must be in ISO 8601 UTC format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["environment", "status"], ["environment"]) + def activate( + self, + guide_key: str, + *, + environment: str, + status: bool | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + until: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + if not guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return self._put( + f"/v1/guides/{guide_key}/activate", + body=maybe_transform( + { + "status": status, + "from_": from_, + "until": until, + }, + guide_activate_params.GuideActivateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"environment": environment}, guide_activate_params.GuideActivateParams), + ), + cast_to=GuideActivateResponse, + ) + + def upsert( + self, + guide_key: str, + *, + environment: str, + guide: guide_upsert_params.Guide, + annotate: bool | NotGiven = NOT_GIVEN, + commit: bool | NotGiven = NOT_GIVEN, + commit_message: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideUpsertResponse: + """ + Updates a guide of a given key, or creates a new one if it does not yet exist. + + Note: this endpoint only operates on guides in the "development" environment. + + Args: + environment: The environment slug. + + guide: A request to create or update a guide. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + commit: Whether to commit the resource at the same time as modifying it. + + commit_message: The message to commit the resource with, only used if `commit` is `true`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return self._put( + f"/v1/guides/{guide_key}", + body=maybe_transform({"guide": guide}, guide_upsert_params.GuideUpsertParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "annotate": annotate, + "commit": commit, + "commit_message": commit_message, + }, + guide_upsert_params.GuideUpsertParams, + ), + ), + cast_to=GuideUpsertResponse, + ) + + def validate( + self, + guide_key: str, + *, + environment: str, + guide: guide_validate_params.Guide, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideValidateResponse: + """ + Validates a guide payload without persisting it. + + Note: Validating a guide is only done in the development environment context. + + Args: + environment: The environment slug. + + guide: A request to create or update a guide. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return self._put( + f"/v1/guides/{guide_key}/validate", + body=maybe_transform({"guide": guide}, guide_validate_params.GuideValidateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"environment": environment}, guide_validate_params.GuideValidateParams), + ), + cast_to=GuideValidateResponse, + ) + + +class AsyncGuidesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncGuidesResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return AsyncGuidesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncGuidesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return AsyncGuidesResourceWithStreamingResponse(self) + + async def retrieve( + self, + guide_key: str, + *, + environment: str, + annotate: bool | NotGiven = NOT_GIVEN, + hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> Guide: + """ + Get a guide by its key. + + Args: + environment: The environment slug. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return await self._get( + f"/v1/guides/{guide_key}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "annotate": annotate, + "hide_uncommitted_changes": hide_uncommitted_changes, + }, + guide_retrieve_params.GuideRetrieveParams, + ), + ), + cast_to=Guide, + ) + + def list( + self, + *, + environment: str, + after: str | NotGiven = NOT_GIVEN, + annotate: bool | NotGiven = NOT_GIVEN, + before: str | NotGiven = NOT_GIVEN, + hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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[Guide, AsyncEntriesCursor[Guide]]: + """ + Returns a paginated list of guides available in a given environment. + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + before: The cursor to fetch entries before. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/guides", + page=AsyncEntriesCursor[Guide], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "annotate": annotate, + "before": before, + "hide_uncommitted_changes": hide_uncommitted_changes, + "limit": limit, + }, + guide_list_params.GuideListParams, + ), + ), + model=Guide, + ) + + @overload + async def activate( + self, + guide_key: str, + *, + environment: str, + status: bool, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + """Activates (or deactivates) a guide in a given environment. + + You can either set + the active status immediately or schedule it. + + Note: This immediately enables or disables a guide in a given environment + without needing to go through environment promotion. + + Args: + environment: The environment slug. + + status: Whether to activate or deactivate the guide. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @overload + async def activate( + self, + guide_key: str, + *, + environment: str, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + until: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + """Activates (or deactivates) a guide in a given environment. + + You can either set + the active status immediately or schedule it. + + Note: This immediately enables or disables a guide in a given environment + without needing to go through environment promotion. + + Args: + environment: The environment slug. + + from_: When to activate the guide. If provided, the guide will be scheduled to activate + at this time. Must be in ISO 8601 UTC format. + + until: When to deactivate the guide. If provided, the guide will be scheduled to + deactivate at this time. Must be in ISO 8601 UTC format. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + ... + + @required_args(["environment", "status"], ["environment"]) + async def activate( + self, + guide_key: str, + *, + environment: str, + status: bool | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | NotGiven = NOT_GIVEN, + until: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideActivateResponse: + if not guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return await self._put( + f"/v1/guides/{guide_key}/activate", + body=await async_maybe_transform( + { + "status": status, + "from_": from_, + "until": until, + }, + guide_activate_params.GuideActivateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"environment": environment}, guide_activate_params.GuideActivateParams + ), + ), + cast_to=GuideActivateResponse, + ) + + async def upsert( + self, + guide_key: str, + *, + environment: str, + guide: guide_upsert_params.Guide, + annotate: bool | NotGiven = NOT_GIVEN, + commit: bool | NotGiven = NOT_GIVEN, + commit_message: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideUpsertResponse: + """ + Updates a guide of a given key, or creates a new one if it does not yet exist. + + Note: this endpoint only operates on guides in the "development" environment. + + Args: + environment: The environment slug. + + guide: A request to create or update a guide. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + commit: Whether to commit the resource at the same time as modifying it. + + commit_message: The message to commit the resource with, only used if `commit` is `true`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return await self._put( + f"/v1/guides/{guide_key}", + body=await async_maybe_transform({"guide": guide}, guide_upsert_params.GuideUpsertParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "annotate": annotate, + "commit": commit, + "commit_message": commit_message, + }, + guide_upsert_params.GuideUpsertParams, + ), + ), + cast_to=GuideUpsertResponse, + ) + + async def validate( + self, + guide_key: str, + *, + environment: str, + guide: guide_validate_params.Guide, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + ) -> GuideValidateResponse: + """ + Validates a guide payload without persisting it. + + Note: Validating a guide is only done in the development environment context. + + Args: + environment: The environment slug. + + guide: A request to create or update a guide. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return await self._put( + f"/v1/guides/{guide_key}/validate", + body=await async_maybe_transform({"guide": guide}, guide_validate_params.GuideValidateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"environment": environment}, guide_validate_params.GuideValidateParams + ), + ), + cast_to=GuideValidateResponse, + ) + + +class GuidesResourceWithRawResponse: + def __init__(self, guides: GuidesResource) -> None: + self._guides = guides + + self.retrieve = to_raw_response_wrapper( + guides.retrieve, + ) + self.list = to_raw_response_wrapper( + guides.list, + ) + self.activate = to_raw_response_wrapper( + guides.activate, + ) + self.upsert = to_raw_response_wrapper( + guides.upsert, + ) + self.validate = to_raw_response_wrapper( + guides.validate, + ) + + +class AsyncGuidesResourceWithRawResponse: + def __init__(self, guides: AsyncGuidesResource) -> None: + self._guides = guides + + self.retrieve = async_to_raw_response_wrapper( + guides.retrieve, + ) + self.list = async_to_raw_response_wrapper( + guides.list, + ) + self.activate = async_to_raw_response_wrapper( + guides.activate, + ) + self.upsert = async_to_raw_response_wrapper( + guides.upsert, + ) + self.validate = async_to_raw_response_wrapper( + guides.validate, + ) + + +class GuidesResourceWithStreamingResponse: + def __init__(self, guides: GuidesResource) -> None: + self._guides = guides + + self.retrieve = to_streamed_response_wrapper( + guides.retrieve, + ) + self.list = to_streamed_response_wrapper( + guides.list, + ) + self.activate = to_streamed_response_wrapper( + guides.activate, + ) + self.upsert = to_streamed_response_wrapper( + guides.upsert, + ) + self.validate = to_streamed_response_wrapper( + guides.validate, + ) + + +class AsyncGuidesResourceWithStreamingResponse: + def __init__(self, guides: AsyncGuidesResource) -> None: + self._guides = guides + + self.retrieve = async_to_streamed_response_wrapper( + guides.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + guides.list, + ) + self.activate = async_to_streamed_response_wrapper( + guides.activate, + ) + self.upsert = async_to_streamed_response_wrapper( + guides.upsert, + ) + self.validate = async_to_streamed_response_wrapper( + guides.validate, + ) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 4356197..28ab0c4 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -2,6 +2,7 @@ from __future__ import annotations +from .guide import Guide as Guide from .commit import Commit as Commit from .shared import PageInfo as PageInfo from .channel import Channel as Channel @@ -10,6 +11,7 @@ from .variable import Variable as Variable from .workflow import Workflow as Workflow from .condition import Condition as Condition +from .guide_step import GuideStep as GuideStep from .environment import Environment as Environment from .send_window import SendWindow as SendWindow from .translation import Translation as Translation @@ -24,14 +26,17 @@ from .email_template import EmailTemplate as EmailTemplate from .condition_group import ConditionGroup as ConditionGroup from .condition_param import ConditionParam as ConditionParam +from .guide_step_param import GuideStepParam as GuideStepParam from .request_template import RequestTemplate as RequestTemplate from .webhook_template import WebhookTemplate as WebhookTemplate +from .guide_list_params import GuideListParams as GuideListParams from .send_window_param import SendWindowParam as SendWindowParam from .channel_group_rule import ChannelGroupRule as ChannelGroupRule from .commit_list_params import CommitListParams as CommitListParams from .sms_template_param import SMSTemplateParam as SMSTemplateParam from .channel_list_params import ChannelListParams as ChannelListParams from .chat_template_param import ChatTemplateParam as ChatTemplateParam +from .guide_upsert_params import GuideUpsertParams as GuideUpsertParams from .partial_list_params import PartialListParams as PartialListParams from .push_template_param import PushTemplateParam as PushTemplateParam from .workflow_batch_step import WorkflowBatchStep as WorkflowBatchStep @@ -49,6 +54,10 @@ from .workflow_list_params import WorkflowListParams as WorkflowListParams from .chat_channel_settings import ChatChannelSettings as ChatChannelSettings from .condition_group_param import ConditionGroupParam as ConditionGroupParam +from .guide_activate_params import GuideActivateParams as GuideActivateParams +from .guide_retrieve_params import GuideRetrieveParams as GuideRetrieveParams +from .guide_upsert_response import GuideUpsertResponse as GuideUpsertResponse +from .guide_validate_params import GuideValidateParams as GuideValidateParams from .partial_upsert_params import PartialUpsertParams as PartialUpsertParams from .push_channel_settings import PushChannelSettings as PushChannelSettings from .workflow_channel_step import WorkflowChannelStep as WorkflowChannelStep @@ -60,6 +69,8 @@ from .workflow_upsert_params import WorkflowUpsertParams as WorkflowUpsertParams from .api_key_exchange_params import APIKeyExchangeParams as APIKeyExchangeParams from .environment_list_params import EnvironmentListParams as EnvironmentListParams +from .guide_activate_response import GuideActivateResponse as GuideActivateResponse +from .guide_validate_response import GuideValidateResponse as GuideValidateResponse from .message_type_text_field import MessageTypeTextField as MessageTypeTextField from .partial_retrieve_params import PartialRetrieveParams as PartialRetrieveParams from .partial_upsert_response import PartialUpsertResponse as PartialUpsertResponse diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py new file mode 100644 index 0000000..252c925 --- /dev/null +++ b/src/knock_mapi/types/guide.py @@ -0,0 +1,86 @@ +# 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 .._models import BaseModel +from .guide_step import GuideStep +from .condition_group import ConditionGroup + +__all__ = ["Guide", "ActivationLocationRule"] + + +class ActivationLocationRule(BaseModel): + directive: Literal["allow", "block"] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: str + """The URL pathname pattern to match against. Must be a valid URI path.""" + + +class Guide(BaseModel): + active: bool + """Whether the guide is active.""" + + created_at: datetime + """The timestamp of when the guide was created.""" + + environment: str + """The slug of the environment in which the guide exists.""" + + key: str + """The unique key string for the guide object. + + Must be at minimum 3 characters and at maximum 255 characters in length. Must be + in the format of ^[a-z0-9_-]+$. + """ + + name: str + """A name for the guide. Must be at maximum 255 characters in length.""" + + sha: str + """The SHA hash of the guide.""" + + updated_at: datetime + """The timestamp of when the guide was last updated.""" + + activation_location_rules: Optional[List[ActivationLocationRule]] = None + """ + A list of activation location rules that describe when the guide should be + shown. + """ + + archived_at: Optional[datetime] = None + """The timestamp of when the guide was archived.""" + + channel_key: Optional[str] = None + """The key of the channel in which the guide exists.""" + + deleted_at: Optional[datetime] = None + """The timestamp of when the guide was deleted.""" + + description: Optional[str] = None + """An arbitrary string attached to a guide object. + + Useful for adding notes about the guide for internal purposes. Maximum of 280 + characters allowed. + """ + + semver: Optional[str] = None + """The semver of the guide.""" + + steps: Optional[List[GuideStep]] = None + """A list of guide step objects in the guide.""" + + target_audience_id: Optional[str] = None + """The ID of the target audience for the guide.""" + + target_property_conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + type: Optional[str] = None + """The type of the guide.""" + + valid: Optional[bool] = None + """Whether the guide is valid.""" diff --git a/src/knock_mapi/types/guide_activate_params.py b/src/knock_mapi/types/guide_activate_params.py new file mode 100644 index 0000000..014236d --- /dev/null +++ b/src/knock_mapi/types/guide_activate_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypeAlias, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["GuideActivateParams", "Variant0", "Variant1"] + + +class Variant0(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + status: Required[bool] + """Whether to activate or deactivate the guide.""" + + +class Variant1(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + from_: Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")] + """When to activate the guide. + + If provided, the guide will be scheduled to activate at this time. Must be in + ISO 8601 UTC format. + """ + + until: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """When to deactivate the guide. + + If provided, the guide will be scheduled to deactivate at this time. Must be in + ISO 8601 UTC format. + """ + + +GuideActivateParams: TypeAlias = Union[Variant0, Variant1] diff --git a/src/knock_mapi/types/guide_activate_response.py b/src/knock_mapi/types/guide_activate_response.py new file mode 100644 index 0000000..2055f16 --- /dev/null +++ b/src/knock_mapi/types/guide_activate_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .guide import Guide +from .._models import BaseModel + +__all__ = ["GuideActivateResponse"] + + +class GuideActivateResponse(BaseModel): + guide: Guide + """ + A guide defines an in-app guide that can be displayed to users based on priority + and other conditions. + """ diff --git a/src/knock_mapi/types/guide_list_params.py b/src/knock_mapi/types/guide_list_params.py new file mode 100644 index 0000000..ae4b83c --- /dev/null +++ b/src/knock_mapi/types/guide_list_params.py @@ -0,0 +1,31 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GuideListParams"] + + +class GuideListParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + after: str + """The cursor to fetch entries after.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + before: str + """The cursor to fetch entries before.""" + + hide_uncommitted_changes: bool + """Whether to hide uncommitted changes. + + When true, only committed changes will be returned. When false, both committed + and uncommitted changes will be returned. + """ + + limit: int + """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/guide_retrieve_params.py b/src/knock_mapi/types/guide_retrieve_params.py new file mode 100644 index 0000000..e012322 --- /dev/null +++ b/src/knock_mapi/types/guide_retrieve_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GuideRetrieveParams"] + + +class GuideRetrieveParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + hide_uncommitted_changes: bool + """Whether to hide uncommitted changes. + + When true, only committed changes will be returned. When false, both committed + and uncommitted changes will be returned. + """ diff --git a/src/knock_mapi/types/guide_step.py b/src/knock_mapi/types/guide_step.py new file mode 100644 index 0000000..31d83a5 --- /dev/null +++ b/src/knock_mapi/types/guide_step.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["GuideStep"] + + +class GuideStep(BaseModel): + ref: str + """The unique reference string for the step. + + Must be at minimum 3 characters and at maximum 255 characters in length. Must be + in the format of ^[a-z0-9_-]+$. + """ + + schema_key: str + """The key of the template schema to use for this step.""" + + schema_semver: str + """The semantic version of the template schema to use.""" + + schema_variant_key: str + """The key of the template schema variant to use.""" + + name: Optional[str] = None + """A name for the step.""" + + values: Optional[object] = None + """A map of values that make up the step's content. + + Each value must conform to its respective template schema field settings. + """ diff --git a/src/knock_mapi/types/guide_step_param.py b/src/knock_mapi/types/guide_step_param.py new file mode 100644 index 0000000..696bccb --- /dev/null +++ b/src/knock_mapi/types/guide_step_param.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["GuideStepParam"] + + +class GuideStepParam(TypedDict, total=False): + ref: Required[str] + """The unique reference string for the step. + + Must be at minimum 3 characters and at maximum 255 characters in length. Must be + in the format of ^[a-z0-9_-]+$. + """ + + schema_key: Required[str] + """The key of the template schema to use for this step.""" + + schema_semver: Required[str] + """The semantic version of the template schema to use.""" + + schema_variant_key: Required[str] + """The key of the template schema variant to use.""" + + name: str + """A name for the step.""" + + values: object + """A map of values that make up the step's content. + + Each value must conform to its respective template schema field settings. + """ diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py new file mode 100644 index 0000000..c961a38 --- /dev/null +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -0,0 +1,80 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo +from .guide_step_param import GuideStepParam +from .condition_group_param import ConditionGroupParam + +__all__ = ["GuideUpsertParams", "Guide", "GuideActivationLocationRule"] + + +class GuideUpsertParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + guide: Required[Guide] + """A request to create or update a guide.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + commit: bool + """Whether to commit the resource at the same time as modifying it.""" + + commit_message: str + """The message to commit the resource with, only used if `commit` is `true`.""" + + +class GuideActivationLocationRule(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" + + +class Guide(TypedDict, total=False): + channel_key: Required[str] + """The key of the channel in which the guide exists.""" + + name: Required[str] + """A name for the guide. Must be at maximum 255 characters in length.""" + + steps: Required[Iterable[GuideStepParam]] + """A list of guide step objects in the guide.""" + + activation_location_rules: Iterable[GuideActivationLocationRule] + """ + A list of activation location rules that describe when the guide should be + shown. + """ + + archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The timestamp of when the guide was archived.""" + + deleted_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The timestamp of when the guide was deleted.""" + + description: Optional[str] + """An arbitrary string attached to a guide object. + + Useful for adding notes about the guide for internal purposes. Maximum of 280 + characters allowed. + """ + + semver: str + """The semver of the guide.""" + + target_audience_id: Optional[str] + """The ID of the target audience for the guide.""" + + target_property_conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + type: str + """The type of the guide.""" diff --git a/src/knock_mapi/types/guide_upsert_response.py b/src/knock_mapi/types/guide_upsert_response.py new file mode 100644 index 0000000..f554cd8 --- /dev/null +++ b/src/knock_mapi/types/guide_upsert_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .guide import Guide +from .._models import BaseModel + +__all__ = ["GuideUpsertResponse"] + + +class GuideUpsertResponse(BaseModel): + guide: Guide + """ + A guide defines an in-app guide that can be displayed to users based on priority + and other conditions. + """ diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py new file mode 100644 index 0000000..0e47833 --- /dev/null +++ b/src/knock_mapi/types/guide_validate_params.py @@ -0,0 +1,71 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable, Optional +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypedDict + +from .._utils import PropertyInfo +from .guide_step_param import GuideStepParam +from .condition_group_param import ConditionGroupParam + +__all__ = ["GuideValidateParams", "Guide", "GuideActivationLocationRule"] + + +class GuideValidateParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + guide: Required[Guide] + """A request to create or update a guide.""" + + +class GuideActivationLocationRule(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" + + +class Guide(TypedDict, total=False): + channel_key: Required[str] + """The key of the channel in which the guide exists.""" + + name: Required[str] + """A name for the guide. Must be at maximum 255 characters in length.""" + + steps: Required[Iterable[GuideStepParam]] + """A list of guide step objects in the guide.""" + + activation_location_rules: Iterable[GuideActivationLocationRule] + """ + A list of activation location rules that describe when the guide should be + shown. + """ + + archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The timestamp of when the guide was archived.""" + + deleted_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The timestamp of when the guide was deleted.""" + + description: Optional[str] + """An arbitrary string attached to a guide object. + + Useful for adding notes about the guide for internal purposes. Maximum of 280 + characters allowed. + """ + + semver: str + """The semver of the guide.""" + + target_audience_id: Optional[str] + """The ID of the target audience for the guide.""" + + target_property_conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + type: str + """The type of the guide.""" diff --git a/src/knock_mapi/types/guide_validate_response.py b/src/knock_mapi/types/guide_validate_response.py new file mode 100644 index 0000000..85ff92a --- /dev/null +++ b/src/knock_mapi/types/guide_validate_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .guide import Guide +from .._models import BaseModel + +__all__ = ["GuideValidateResponse"] + + +class GuideValidateResponse(BaseModel): + guide: Guide + """ + A guide defines an in-app guide that can be displayed to users based on priority + and other conditions. + """ diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 62e63e4..95db0fe 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -5,7 +5,13 @@ from typing import Dict, List, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "WorkflowRunParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class WorkflowRunParams(TypedDict, total=False): @@ -31,19 +37,19 @@ class WorkflowRunParams(TypedDict, total=False): """The tenant to associate the workflow run with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index c35479d..d6b03c2 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -5,7 +5,13 @@ from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["StepPreviewTemplateParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "StepPreviewTemplateParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class StepPreviewTemplateParams(TypedDict, total=False): @@ -33,19 +39,19 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The tenant to associate the workflow with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py new file mode 100644 index 0000000..4c6f244 --- /dev/null +++ b/tests/api_resources/test_guides.py @@ -0,0 +1,1123 @@ +# 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 knock_mapi import KnockMgmt, AsyncKnockMgmt +from tests.utils import assert_matches_type +from knock_mapi.types import ( + Guide, + GuideUpsertResponse, + GuideActivateResponse, + GuideValidateResponse, +) +from knock_mapi._utils import parse_datetime +from knock_mapi.pagination import SyncEntriesCursor, AsyncEntriesCursor + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestGuides: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_retrieve(self, client: KnockMgmt) -> None: + guide = client.guides.retrieve( + guide_key="guide_key", + environment="development", + ) + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: + guide = client.guides.retrieve( + guide_key="guide_key", + environment="development", + annotate=True, + hide_uncommitted_changes=True, + ) + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_retrieve(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.retrieve( + guide_key="guide_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.retrieve( + guide_key="guide_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(Guide, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_path_params_retrieve(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.retrieve( + guide_key="", + environment="development", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_list(self, client: KnockMgmt) -> None: + guide = client.guides.list( + environment="development", + ) + assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_list_with_all_params(self, client: KnockMgmt) -> None: + guide = client.guides.list( + environment="development", + after="after", + annotate=True, + before="before", + hide_uncommitted_changes=True, + limit=0, + ) + assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_list(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_list(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_activate_overload_1(self, client: KnockMgmt) -> None: + guide = client.guides.activate( + guide_key="guide_key", + environment="development", + status=True, + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_activate_overload_1(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.activate( + guide_key="guide_key", + environment="development", + status=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_activate_overload_1(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.activate( + guide_key="guide_key", + environment="development", + status=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_path_params_activate_overload_1(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.activate( + guide_key="", + environment="development", + status=True, + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_activate_overload_2(self, client: KnockMgmt) -> None: + guide = client.guides.activate( + guide_key="guide_key", + environment="development", + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_activate_with_all_params_overload_2(self, client: KnockMgmt) -> None: + guide = client.guides.activate( + guide_key="guide_key", + environment="development", + from_=parse_datetime("2024-03-20T10:00:00Z"), + until=parse_datetime("2024-03-21T10:00:00Z"), + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_activate_overload_2(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.activate( + guide_key="guide_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_activate_overload_2(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.activate( + guide_key="guide_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_path_params_activate_overload_2(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.activate( + guide_key="", + environment="development", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_upsert(self, client: KnockMgmt) -> None: + guide = client.guides.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: + guide = client.guides.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + "name": "Welcome to the App", + "values": {"text_field": "value"}, + } + ], + "activation_location_rules": [ + { + "directive": "allow", + "pathname": "/dashboard/*", + } + ], + "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "description": "A guide to help users get started with the application", + "semver": "semver", + "target_audience_id": None, + "target_property_conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "type": "type", + }, + annotate=True, + commit=True, + commit_message="commit_message", + ) + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_upsert(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_upsert(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_path_params_upsert(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.upsert( + guide_key="", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_validate(self, client: KnockMgmt) -> None: + guide = client.guides.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: + guide = client.guides.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + "name": "Welcome to the App", + "values": {"text_field": "value"}, + } + ], + "activation_location_rules": [ + { + "directive": "allow", + "pathname": "/dashboard/*", + } + ], + "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "description": "A guide to help users get started with the application", + "semver": "semver", + "target_audience_id": None, + "target_property_conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "type": "type", + }, + ) + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_raw_response_validate(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_streaming_response_validate(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + def test_path_params_validate(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.validate( + guide_key="", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + +class TestAsyncGuides: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.retrieve( + guide_key="guide_key", + environment="development", + ) + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.retrieve( + guide_key="guide_key", + environment="development", + annotate=True, + hide_uncommitted_changes=True, + ) + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.retrieve( + guide_key="guide_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(Guide, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.retrieve( + guide_key="guide_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(Guide, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.retrieve( + guide_key="", + environment="development", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.list( + environment="development", + ) + assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.list( + environment="development", + after="after", + annotate=True, + before="before", + hide_uncommitted_changes=True, + limit=0, + ) + assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.activate( + guide_key="guide_key", + environment="development", + status=True, + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.activate( + guide_key="guide_key", + environment="development", + status=True, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.activate( + guide_key="guide_key", + environment="development", + status=True, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_path_params_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.activate( + guide_key="", + environment="development", + status=True, + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.activate( + guide_key="guide_key", + environment="development", + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_activate_with_all_params_overload_2(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.activate( + guide_key="guide_key", + environment="development", + from_=parse_datetime("2024-03-20T10:00:00Z"), + until=parse_datetime("2024-03-21T10:00:00Z"), + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.activate( + guide_key="guide_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.activate( + guide_key="guide_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_path_params_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.activate( + guide_key="", + environment="development", + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + "name": "Welcome to the App", + "values": {"text_field": "value"}, + } + ], + "activation_location_rules": [ + { + "directive": "allow", + "pathname": "/dashboard/*", + } + ], + "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "description": "A guide to help users get started with the application", + "semver": "semver", + "target_audience_id": None, + "target_property_conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "type": "type", + }, + annotate=True, + commit=True, + commit_message="commit_message", + ) + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.upsert( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(GuideUpsertResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.upsert( + guide_key="", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + "name": "Welcome to the App", + "values": {"text_field": "value"}, + } + ], + "activation_location_rules": [ + { + "directive": "allow", + "pathname": "/dashboard/*", + } + ], + "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "description": "A guide to help users get started with the application", + "semver": "semver", + "target_audience_id": None, + "target_property_conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "type": "type", + }, + ) + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.validate( + guide_key="guide_key", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(GuideValidateResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip( + reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" + ) + @parametrize + async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.validate( + guide_key="", + environment="development", + guide={ + "channel_key": "in-app-guide", + "name": "Getting Started Guide", + "steps": [ + { + "ref": "welcome-step", + "schema_key": "tooltip", + "schema_semver": "1.0.0", + "schema_variant_key": "default", + } + ], + }, + ) From 29415bd6f87d68167f11ce4aaa71cff02fa55460 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:31:11 +0000 Subject: [PATCH 027/101] feat(api): manual updates --- .stats.yml | 6 +++--- src/knock_mapi/types/workflow_run_params.py | 16 +++++----------- .../workflows/step_preview_template_params.py | 16 +++++----------- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/.stats.yml b/.stats.yml index 34f6cfa..f35b322 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-604e7da30835c75d1659200bff074f2551f805ca2a0a83265ee422a7ac61b919.yml -openapi_spec_hash: f15fb2c57a561ece4231ea3052d6db27 -config_hash: acee12c9c8095ab1f2abc4972c70821a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml +openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 +config_hash: 765a634232fe72790f5bcf079b4950a1 diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 95db0fe..62e63e4 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -5,13 +5,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = [ - "WorkflowRunParams", - "Recipient", - "RecipientObjectRecipientReference", - "Actor", - "ActorObjectRecipientReference", -] +__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] class WorkflowRunParams(TypedDict, total=False): @@ -37,19 +31,19 @@ class WorkflowRunParams(TypedDict, total=False): """The tenant to associate the workflow run with.""" -class RecipientObjectRecipientReference(TypedDict, total=False): +class RecipientUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] +Recipient: TypeAlias = Union[str, RecipientUnionMember1] -class ActorObjectRecipientReference(TypedDict, total=False): +class ActorUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorObjectRecipientReference] +Actor: TypeAlias = Union[str, ActorUnionMember1] diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index d6b03c2..c35479d 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -5,13 +5,7 @@ from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = [ - "StepPreviewTemplateParams", - "Recipient", - "RecipientObjectRecipientReference", - "Actor", - "ActorObjectRecipientReference", -] +__all__ = ["StepPreviewTemplateParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] class StepPreviewTemplateParams(TypedDict, total=False): @@ -39,19 +33,19 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The tenant to associate the workflow with.""" -class RecipientObjectRecipientReference(TypedDict, total=False): +class RecipientUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] +Recipient: TypeAlias = Union[str, RecipientUnionMember1] -class ActorObjectRecipientReference(TypedDict, total=False): +class ActorUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorObjectRecipientReference] +Actor: TypeAlias = Union[str, ActorUnionMember1] From b06ccba6f9b3791a6cbbbd19ad9b27fbceed0067 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:38:08 +0000 Subject: [PATCH 028/101] feat(api): latest spec and config --- .stats.yml | 6 +++--- api.md | 1 + src/knock_mapi/types/__init__.py | 2 ++ src/knock_mapi/types/guide.py | 14 +++----------- .../types/guide_activation_location_rule.py | 15 +++++++++++++++ .../guide_activation_location_rule_param.py | 15 +++++++++++++++ src/knock_mapi/types/guide_step.py | 4 ++-- src/knock_mapi/types/guide_step_param.py | 3 ++- src/knock_mapi/types/guide_upsert_params.py | 15 ++++----------- src/knock_mapi/types/guide_validate_params.py | 15 ++++----------- src/knock_mapi/types/workflow_run_params.py | 16 +++++++++++----- .../workflows/step_preview_template_params.py | 16 +++++++++++----- tests/api_resources/test_guides.py | 8 ++++---- 13 files changed, 77 insertions(+), 53 deletions(-) create mode 100644 src/knock_mapi/types/guide_activation_location_rule.py create mode 100644 src/knock_mapi/types/guide_activation_location_rule_param.py diff --git a/.stats.yml b/.stats.yml index f35b322..6a63e36 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml -openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 -config_hash: 765a634232fe72790f5bcf079b4950a1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-16fad60e4cc81d514d6978e026860beab37ca6b3ba326a8569685e54187495e6.yml +openapi_spec_hash: 842e7da8bade37a353f41113cc675fa0 +config_hash: f9e83854b42d2264516f449568348afa diff --git a/api.md b/api.md index f48b15f..343c550 100644 --- a/api.md +++ b/api.md @@ -246,6 +246,7 @@ Types: ```python from knock_mapi.types import ( Guide, + GuideActivationLocationRule, GuideStep, GuideActivateResponse, GuideUpsertResponse, diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 28ab0c4..0f7097b 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -121,7 +121,9 @@ from .translation_retrieve_response import TranslationRetrieveResponse as TranslationRetrieveResponse from .translation_validate_response import TranslationValidateResponse as TranslationValidateResponse from .email_layout_validate_response import EmailLayoutValidateResponse as EmailLayoutValidateResponse +from .guide_activation_location_rule import GuideActivationLocationRule as GuideActivationLocationRule from .message_type_validate_response import MessageTypeValidateResponse as MessageTypeValidateResponse from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep as WorkflowTriggerWorkflowStep from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam as InAppFeedChannelSettingsParam +from .guide_activation_location_rule_param import GuideActivationLocationRuleParam as GuideActivationLocationRuleParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam as WorkflowTriggerWorkflowStepParam diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py index 252c925..0b7d0df 100644 --- a/src/knock_mapi/types/guide.py +++ b/src/knock_mapi/types/guide.py @@ -2,21 +2,13 @@ from typing import List, Optional from datetime import datetime -from typing_extensions import Literal from .._models import BaseModel from .guide_step import GuideStep from .condition_group import ConditionGroup +from .guide_activation_location_rule import GuideActivationLocationRule -__all__ = ["Guide", "ActivationLocationRule"] - - -class ActivationLocationRule(BaseModel): - directive: Literal["allow", "block"] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: str - """The URL pathname pattern to match against. Must be a valid URI path.""" +__all__ = ["Guide"] class Guide(BaseModel): @@ -45,7 +37,7 @@ class Guide(BaseModel): updated_at: datetime """The timestamp of when the guide was last updated.""" - activation_location_rules: Optional[List[ActivationLocationRule]] = None + activation_location_rules: Optional[List[GuideActivationLocationRule]] = None """ A list of activation location rules that describe when the guide should be shown. diff --git a/src/knock_mapi/types/guide_activation_location_rule.py b/src/knock_mapi/types/guide_activation_location_rule.py new file mode 100644 index 0000000..78e060b --- /dev/null +++ b/src/knock_mapi/types/guide_activation_location_rule.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["GuideActivationLocationRule"] + + +class GuideActivationLocationRule(BaseModel): + directive: Literal["allow", "block"] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: str + """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_activation_location_rule_param.py b/src/knock_mapi/types/guide_activation_location_rule_param.py new file mode 100644 index 0000000..c58bd8d --- /dev/null +++ b/src/knock_mapi/types/guide_activation_location_rule_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["GuideActivationLocationRuleParam"] + + +class GuideActivationLocationRuleParam(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_step.py b/src/knock_mapi/types/guide_step.py index 31d83a5..00fdd38 100644 --- a/src/knock_mapi/types/guide_step.py +++ b/src/knock_mapi/types/guide_step.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Optional from .._models import BaseModel @@ -27,7 +27,7 @@ class GuideStep(BaseModel): name: Optional[str] = None """A name for the step.""" - values: Optional[object] = None + values: Optional[Dict[str, object]] = None """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/guide_step_param.py b/src/knock_mapi/types/guide_step_param.py index 696bccb..bac89bc 100644 --- a/src/knock_mapi/types/guide_step_param.py +++ b/src/knock_mapi/types/guide_step_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Dict from typing_extensions import Required, TypedDict __all__ = ["GuideStepParam"] @@ -27,7 +28,7 @@ class GuideStepParam(TypedDict, total=False): name: str """A name for the step.""" - values: object + values: Dict[str, object] """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index c961a38..1f2a49e 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -4,13 +4,14 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam +from .guide_activation_location_rule_param import GuideActivationLocationRuleParam -__all__ = ["GuideUpsertParams", "Guide", "GuideActivationLocationRule"] +__all__ = ["GuideUpsertParams", "Guide"] class GuideUpsertParams(TypedDict, total=False): @@ -30,14 +31,6 @@ class GuideUpsertParams(TypedDict, total=False): """The message to commit the resource with, only used if `commit` is `true`.""" -class GuideActivationLocationRule(TypedDict, total=False): - directive: Required[Literal["allow", "block"]] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: Required[str] - """The URL pathname pattern to match against. Must be a valid URI path.""" - - class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -48,7 +41,7 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_location_rules: Iterable[GuideActivationLocationRule] + activation_location_rules: Iterable[GuideActivationLocationRuleParam] """ A list of activation location rules that describe when the guide should be shown. diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index 0e47833..3a40ea8 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -4,13 +4,14 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam +from .guide_activation_location_rule_param import GuideActivationLocationRuleParam -__all__ = ["GuideValidateParams", "Guide", "GuideActivationLocationRule"] +__all__ = ["GuideValidateParams", "Guide"] class GuideValidateParams(TypedDict, total=False): @@ -21,14 +22,6 @@ class GuideValidateParams(TypedDict, total=False): """A request to create or update a guide.""" -class GuideActivationLocationRule(TypedDict, total=False): - directive: Required[Literal["allow", "block"]] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: Required[str] - """The URL pathname pattern to match against. Must be a valid URI path.""" - - class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -39,7 +32,7 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_location_rules: Iterable[GuideActivationLocationRule] + activation_location_rules: Iterable[GuideActivationLocationRuleParam] """ A list of activation location rules that describe when the guide should be shown. diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 62e63e4..95db0fe 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -5,7 +5,13 @@ from typing import Dict, List, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "WorkflowRunParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class WorkflowRunParams(TypedDict, total=False): @@ -31,19 +37,19 @@ class WorkflowRunParams(TypedDict, total=False): """The tenant to associate the workflow run with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index c35479d..d6b03c2 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -5,7 +5,13 @@ from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["StepPreviewTemplateParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "StepPreviewTemplateParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class StepPreviewTemplateParams(TypedDict, total=False): @@ -33,19 +39,19 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The tenant to associate the workflow with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index 4c6f244..90b5071 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -312,7 +312,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -463,7 +463,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -864,7 +864,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -1015,7 +1015,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ From 11d9193173be598000253571040bd523128ea457 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:09:13 +0000 Subject: [PATCH 029/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/guide_step.py | 4 ++-- src/knock_mapi/types/guide_step_param.py | 3 +-- src/knock_mapi/types/workflow_run_params.py | 16 +++++----------- .../workflows/step_preview_template_params.py | 16 +++++----------- tests/api_resources/test_guides.py | 8 ++++---- 6 files changed, 19 insertions(+), 32 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6a63e36..740edac 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-16fad60e4cc81d514d6978e026860beab37ca6b3ba326a8569685e54187495e6.yml -openapi_spec_hash: 842e7da8bade37a353f41113cc675fa0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml +openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/guide_step.py b/src/knock_mapi/types/guide_step.py index 00fdd38..31d83a5 100644 --- a/src/knock_mapi/types/guide_step.py +++ b/src/knock_mapi/types/guide_step.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Optional from .._models import BaseModel @@ -27,7 +27,7 @@ class GuideStep(BaseModel): name: Optional[str] = None """A name for the step.""" - values: Optional[Dict[str, object]] = None + values: Optional[object] = None """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/guide_step_param.py b/src/knock_mapi/types/guide_step_param.py index bac89bc..696bccb 100644 --- a/src/knock_mapi/types/guide_step_param.py +++ b/src/knock_mapi/types/guide_step_param.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import Dict from typing_extensions import Required, TypedDict __all__ = ["GuideStepParam"] @@ -28,7 +27,7 @@ class GuideStepParam(TypedDict, total=False): name: str """A name for the step.""" - values: Dict[str, object] + values: object """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 95db0fe..62e63e4 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -5,13 +5,7 @@ from typing import Dict, List, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = [ - "WorkflowRunParams", - "Recipient", - "RecipientObjectRecipientReference", - "Actor", - "ActorObjectRecipientReference", -] +__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] class WorkflowRunParams(TypedDict, total=False): @@ -37,19 +31,19 @@ class WorkflowRunParams(TypedDict, total=False): """The tenant to associate the workflow run with.""" -class RecipientObjectRecipientReference(TypedDict, total=False): +class RecipientUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] +Recipient: TypeAlias = Union[str, RecipientUnionMember1] -class ActorObjectRecipientReference(TypedDict, total=False): +class ActorUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorObjectRecipientReference] +Actor: TypeAlias = Union[str, ActorUnionMember1] diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index d6b03c2..c35479d 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -5,13 +5,7 @@ from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = [ - "StepPreviewTemplateParams", - "Recipient", - "RecipientObjectRecipientReference", - "Actor", - "ActorObjectRecipientReference", -] +__all__ = ["StepPreviewTemplateParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] class StepPreviewTemplateParams(TypedDict, total=False): @@ -39,19 +33,19 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The tenant to associate the workflow with.""" -class RecipientObjectRecipientReference(TypedDict, total=False): +class RecipientUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] +Recipient: TypeAlias = Union[str, RecipientUnionMember1] -class ActorObjectRecipientReference(TypedDict, total=False): +class ActorUnionMember1(TypedDict, total=False): id: Required[str] collection: Required[str] -Actor: TypeAlias = Union[str, ActorObjectRecipientReference] +Actor: TypeAlias = Union[str, ActorUnionMember1] diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index 90b5071..4c6f244 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -312,7 +312,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "bar"}, + "values": {"text_field": "value"}, } ], "activation_location_rules": [ @@ -463,7 +463,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "bar"}, + "values": {"text_field": "value"}, } ], "activation_location_rules": [ @@ -864,7 +864,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "bar"}, + "values": {"text_field": "value"}, } ], "activation_location_rules": [ @@ -1015,7 +1015,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "bar"}, + "values": {"text_field": "value"}, } ], "activation_location_rules": [ From 7af3170696535565aa1d576d1dbc754b0e64ff81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:58:35 +0000 Subject: [PATCH 030/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/guide.py | 10 ++++++++-- src/knock_mapi/types/guide_activate_params.py | 8 ++++---- src/knock_mapi/types/guide_step.py | 4 ++-- src/knock_mapi/types/guide_step_param.py | 3 ++- src/knock_mapi/types/guide_upsert_params.py | 11 ++++------ src/knock_mapi/types/guide_validate_params.py | 11 ++++------ src/knock_mapi/types/workflow_run_params.py | 20 ++++++++++++++----- .../workflows/step_preview_template_params.py | 20 ++++++++++++++----- tests/api_resources/test_guides.py | 16 ++++----------- 10 files changed, 60 insertions(+), 47 deletions(-) diff --git a/.stats.yml b/.stats.yml index 740edac..168671e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e022d24c554645152652e9cd8cb232bce00e4fec5f13bd1c4156d4f7e89ca521.yml -openapi_spec_hash: 46b8b663843203cbd835a119a7e4ec25 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-4982d1d419083979db670bfb999c7422e4b10d88e552cbab3f35775f2198daec.yml +openapi_spec_hash: 28aaf067aecb189fc8c6428d78e8b1c0 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py index 0b7d0df..12aaff1 100644 --- a/src/knock_mapi/types/guide.py +++ b/src/knock_mapi/types/guide.py @@ -66,13 +66,19 @@ class Guide(BaseModel): """A list of guide step objects in the guide.""" target_audience_id: Optional[str] = None - """The ID of the target audience for the guide.""" + """The ID of the target audience for the guide. + + When not set, will default to targeting all users. + """ target_property_conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" type: Optional[str] = None - """The type of the guide.""" + """The type of the guide. + + This is derived from the message type of the guide steps. + """ valid: Optional[bool] = None """Whether the guide is valid.""" diff --git a/src/knock_mapi/types/guide_activate_params.py b/src/knock_mapi/types/guide_activate_params.py index 014236d..2c2e33e 100644 --- a/src/knock_mapi/types/guide_activate_params.py +++ b/src/knock_mapi/types/guide_activate_params.py @@ -8,10 +8,10 @@ from .._utils import PropertyInfo -__all__ = ["GuideActivateParams", "Variant0", "Variant1"] +__all__ = ["GuideActivateParams", "GuideBooleanActivationParams", "GuideScheduledActivationParams"] -class Variant0(TypedDict, total=False): +class GuideBooleanActivationParams(TypedDict, total=False): environment: Required[str] """The environment slug.""" @@ -19,7 +19,7 @@ class Variant0(TypedDict, total=False): """Whether to activate or deactivate the guide.""" -class Variant1(TypedDict, total=False): +class GuideScheduledActivationParams(TypedDict, total=False): environment: Required[str] """The environment slug.""" @@ -38,4 +38,4 @@ class Variant1(TypedDict, total=False): """ -GuideActivateParams: TypeAlias = Union[Variant0, Variant1] +GuideActivateParams: TypeAlias = Union[GuideBooleanActivationParams, GuideScheduledActivationParams] diff --git a/src/knock_mapi/types/guide_step.py b/src/knock_mapi/types/guide_step.py index 31d83a5..00fdd38 100644 --- a/src/knock_mapi/types/guide_step.py +++ b/src/knock_mapi/types/guide_step.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Optional from .._models import BaseModel @@ -27,7 +27,7 @@ class GuideStep(BaseModel): name: Optional[str] = None """A name for the step.""" - values: Optional[object] = None + values: Optional[Dict[str, object]] = None """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/guide_step_param.py b/src/knock_mapi/types/guide_step_param.py index 696bccb..bac89bc 100644 --- a/src/knock_mapi/types/guide_step_param.py +++ b/src/knock_mapi/types/guide_step_param.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import Dict from typing_extensions import Required, TypedDict __all__ = ["GuideStepParam"] @@ -27,7 +28,7 @@ class GuideStepParam(TypedDict, total=False): name: str """A name for the step.""" - values: object + values: Dict[str, object] """A map of values that make up the step's content. Each value must conform to its respective template schema field settings. diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index 1f2a49e..a793a78 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -60,14 +60,11 @@ class Guide(TypedDict, total=False): characters allowed. """ - semver: str - """The semver of the guide.""" - target_audience_id: Optional[str] - """The ID of the target audience for the guide.""" + """The ID of the target audience for the guide. + + When not set, will default to targeting all users. + """ target_property_conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" - - type: str - """The type of the guide.""" diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index 3a40ea8..0bde9b9 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -51,14 +51,11 @@ class Guide(TypedDict, total=False): characters allowed. """ - semver: str - """The semver of the guide.""" - target_audience_id: Optional[str] - """The ID of the target audience for the guide.""" + """The ID of the target audience for the guide. + + When not set, will default to targeting all users. + """ target_property_conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" - - type: str - """The type of the guide.""" diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 62e63e4..a9c4052 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -5,7 +5,13 @@ from typing import Dict, List, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "WorkflowRunParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class WorkflowRunParams(TypedDict, total=False): @@ -31,19 +37,23 @@ class WorkflowRunParams(TypedDict, total=False): """The tenant to associate the workflow run with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] + """The ID of the object.""" collection: Required[str] + """The collection of the object.""" -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] + """The ID of the object.""" collection: Required[str] + """The collection of the object.""" -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index c35479d..23c9619 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -5,7 +5,13 @@ from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict -__all__ = ["StepPreviewTemplateParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"] +__all__ = [ + "StepPreviewTemplateParams", + "Recipient", + "RecipientObjectRecipientReference", + "Actor", + "ActorObjectRecipientReference", +] class StepPreviewTemplateParams(TypedDict, total=False): @@ -33,19 +39,23 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The tenant to associate the workflow with.""" -class RecipientUnionMember1(TypedDict, total=False): +class RecipientObjectRecipientReference(TypedDict, total=False): id: Required[str] + """The ID of the object.""" collection: Required[str] + """The collection of the object.""" -Recipient: TypeAlias = Union[str, RecipientUnionMember1] +Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference] -class ActorUnionMember1(TypedDict, total=False): +class ActorObjectRecipientReference(TypedDict, total=False): id: Required[str] + """The ID of the object.""" collection: Required[str] + """The collection of the object.""" -Actor: TypeAlias = Union[str, ActorUnionMember1] +Actor: TypeAlias = Union[str, ActorObjectRecipientReference] diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index 4c6f244..2c00570 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -312,7 +312,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -324,7 +324,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), "description": "A guide to help users get started with the application", - "semver": "semver", "target_audience_id": None, "target_property_conditions": { "all": [ @@ -335,7 +334,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: } ] }, - "type": "type", }, annotate=True, commit=True, @@ -463,7 +461,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -475,7 +473,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), "description": "A guide to help users get started with the application", - "semver": "semver", "target_audience_id": None, "target_property_conditions": { "all": [ @@ -486,7 +483,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: } ] }, - "type": "type", }, ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) @@ -864,7 +860,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -876,7 +872,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), "description": "A guide to help users get started with the application", - "semver": "semver", "target_audience_id": None, "target_property_conditions": { "all": [ @@ -887,7 +882,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) } ] }, - "type": "type", }, annotate=True, commit=True, @@ -1015,7 +1009,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "schema_semver": "1.0.0", "schema_variant_key": "default", "name": "Welcome to the App", - "values": {"text_field": "value"}, + "values": {"text_field": "bar"}, } ], "activation_location_rules": [ @@ -1027,7 +1021,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "archived_at": parse_datetime("2019-12-27T18:11:19.117Z"), "deleted_at": parse_datetime("2019-12-27T18:11:19.117Z"), "description": "A guide to help users get started with the application", - "semver": "semver", "target_audience_id": None, "target_property_conditions": { "all": [ @@ -1038,7 +1031,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm } ] }, - "type": "type", }, ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) From a2de1b8da15d469c9050b7d814dc2276a7dde6cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:37:31 +0000 Subject: [PATCH 031/101] feat(api): api update --- requirements-dev.lock | 2 +- requirements.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 693543e..5b18689 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -56,7 +56,7 @@ httpx==0.28.1 # via httpx-aiohttp # via knock-mapi # via respx -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via knock-mapi idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index 6da1848..74dfdd3 100644 --- a/requirements.lock +++ b/requirements.lock @@ -43,7 +43,7 @@ httpcore==1.0.2 httpx==0.28.1 # via httpx-aiohttp # via knock-mapi -httpx-aiohttp==0.1.6 +httpx-aiohttp==0.1.8 # via knock-mapi idna==3.4 # via anyio From 588b0db20d8c99e58aa2dab225095bde288c6e35 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:34:24 +0000 Subject: [PATCH 032/101] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 168671e..413cb0a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-4982d1d419083979db670bfb999c7422e4b10d88e552cbab3f35775f2198daec.yml -openapi_spec_hash: 28aaf067aecb189fc8c6428d78e8b1c0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-2cb35d96ed42e88afa277ecac1af19c7602e0c4c51103273488f76b249ccbafc.yml +openapi_spec_hash: 0ce501bc5d851779fe26a53bcd81478b config_hash: f9e83854b42d2264516f449568348afa From b0cf9fcb27c993980e3da9aa6a886efae70c8c38 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:18:35 +0000 Subject: [PATCH 033/101] feat(api): api update --- pyproject.toml | 1 + requirements-dev.lock | 4 ++-- requirements.lock | 4 ++-- src/knock_mapi/_models.py | 13 ++++++----- tests/test_models.py | 45 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 688540e..967585d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", diff --git a/requirements-dev.lock b/requirements-dev.lock index 5b18689..96238fe 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -48,9 +48,9 @@ filelock==3.12.4 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via httpx-aiohttp diff --git a/requirements.lock b/requirements.lock index 74dfdd3..2461e81 100644 --- a/requirements.lock +++ b/requirements.lock @@ -36,9 +36,9 @@ exceptiongroup==1.2.2 frozenlist==1.6.2 # via aiohttp # via aiosignal -h11==0.14.0 +h11==0.16.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.9 # via httpx httpx==0.28.1 # via httpx-aiohttp diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 4f21498..528d568 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -2,9 +2,10 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast +from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( + List, Unpack, Literal, ClassVar, @@ -366,7 +367,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") - return construct_type(value=value, type_=type_) + return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) def is_basemodel(type_: type) -> bool: @@ -420,7 +421,7 @@ def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: return cast(_T, construct_type(value=value, type_=type_)) -def construct_type(*, value: object, type_: object) -> object: +def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: """Loose coercion to the expected type with construction of nested values. If the given value does not match the expected type then it is returned as-is. @@ -438,8 +439,10 @@ def construct_type(*, value: object, type_: object) -> object: type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): - meta: tuple[Any, ...] = get_args(type_)[1:] + if metadata is not None: + meta: tuple[Any, ...] = tuple(metadata) + elif is_annotated_type(type_): + meta = get_args(type_)[1:] type_ = extract_type_arg(type_, 0) else: meta = tuple() diff --git a/tests/test_models.py b/tests/test_models.py index 0bb400d..d662e08 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -889,3 +889,48 @@ class ModelB(BaseModel): ) assert isinstance(m, ModelB) + + +def test_nested_discriminated_union() -> None: + class InnerType1(BaseModel): + type: Literal["type_1"] + + class InnerModel(BaseModel): + inner_value: str + + class InnerType2(BaseModel): + type: Literal["type_2"] + some_inner_model: InnerModel + + class Type1(BaseModel): + base_type: Literal["base_type_1"] + value: Annotated[ + Union[ + InnerType1, + InnerType2, + ], + PropertyInfo(discriminator="type"), + ] + + class Type2(BaseModel): + base_type: Literal["base_type_2"] + + T = Annotated[ + Union[ + Type1, + Type2, + ], + PropertyInfo(discriminator="base_type"), + ] + + model = construct_type( + type_=T, + value={ + "base_type": "base_type_1", + "value": { + "type": "type_2", + }, + }, + ) + assert isinstance(model, Type1) + assert isinstance(model.value, InnerType2) From 0bfd0143c63ab168dcb28f5b49e251f05cfbc6f3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 19:02:41 +0000 Subject: [PATCH 034/101] feat(api): api update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93c3ec3..28087f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Knock Mgmt Python API library -[![PyPI version]()](https://pypi.org/project/knock_mapi/) + +[![PyPI version](https://img.shields.io/pypi/v/knock_mapi.svg?label=pypi%20(stable))](https://pypi.org/project/knock_mapi/) The Knock Mgmt Python library provides convenient access to the Knock Mgmt REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, From a65462cbf700ce4955f56b2e670eaa1f2219d78e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:40:24 +0000 Subject: [PATCH 035/101] feat(api): api update --- pyproject.toml | 2 +- src/knock_mapi/_base_client.py | 11 +++++++++-- tests/test_client.py | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 967585d..ac40ca0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Homepage = "https://github.com/knocklabs/knock-mgmt-python" Repository = "https://github.com/knocklabs/knock-mgmt-python" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] [tool.rye] managed = true diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index 3534752..be0561e 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -529,6 +529,15 @@ def _build_request( # work around https://github.com/encode/httpx/discussions/2880 kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} + is_body_allowed = options.method.lower() != "get" + + if is_body_allowed: + kwargs["json"] = json_data if is_given(json_data) else None + kwargs["files"] = files + else: + headers.pop("Content-Type", None) + kwargs.pop("data", None) + # TODO: report this error to httpx return self._client.build_request( # pyright: ignore[reportUnknownMemberType] headers=headers, @@ -540,8 +549,6 @@ def _build_request( # so that passing a `TypedDict` doesn't cause an error. # https://github.com/microsoft/pyright/issues/3526#event-6715453066 params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - json=json_data if is_given(json_data) else None, - files=files, **kwargs, ) diff --git a/tests/test_client.py b/tests/test_client.py index de00cd2..1245096 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -477,7 +477,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, client: KnockMgmt) -> None: request = client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, @@ -1303,7 +1303,7 @@ def test_request_extra_query(self) -> None: def test_multipart_repeating_array(self, async_client: AsyncKnockMgmt) -> None: request = async_client._build_request( FinalRequestOptions.construct( - method="get", + method="post", url="/foo", headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, json_data={"array": ["foo", "bar"]}, From 7c582f2a91271f759be8f01e15d33f0652012ff7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 14:16:04 +0000 Subject: [PATCH 036/101] feat(api): api update --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 28087f4..91e6336 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ pip install 'knock_mapi[aiohttp] @ git+ssh://git@github.com/knocklabs/knock-mgmt Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python -import os import asyncio from knock_mapi import DefaultAioHttpClient from knock_mapi import AsyncKnockMgmt @@ -94,9 +93,7 @@ from knock_mapi import AsyncKnockMgmt async def main() -> None: async with AsyncKnockMgmt( - service_token=os.environ.get( - "KNOCK_SERVICE_TOKEN" - ), # This is the default and can be omitted + service_token="My Service Token", http_client=DefaultAioHttpClient(), ) as client: page = await client.workflows.list( From 23775502141f16fd94989dd3124107e2db4bf0e9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 14:31:25 +0000 Subject: [PATCH 037/101] feat(api): api update --- src/knock_mapi/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 528d568..ffcbf67 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -439,7 +439,7 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None: + if metadata is not None and len(metadata) > 0: meta: tuple[Any, ...] = tuple(metadata) elif is_annotated_type(type_): meta = get_args(type_)[1:] From 17498d45291c5d7518d490947d00ccd1fd4cc055 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 03:26:49 +0000 Subject: [PATCH 038/101] chore(types): rebuild Pydantic models after all types are defined --- src/knock_mapi/types/__init__.py | 25 +++++++++++++++++++ src/knock_mapi/types/workflow.py | 8 ------ .../types/workflow_activate_response.py | 6 ----- src/knock_mapi/types/workflow_branch_step.py | 8 ------ .../types/workflow_upsert_response.py | 6 ----- .../types/workflow_validate_response.py | 6 ----- 6 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 0f7097b..613e8d1 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -2,6 +2,14 @@ from __future__ import annotations +from . import ( + workflow, + workflow_branch_step, + workflow_upsert_response, + workflow_activate_response, + workflow_validate_response, +) +from .. import _compat from .guide import Guide as Guide from .commit import Commit as Commit from .shared import PageInfo as PageInfo @@ -127,3 +135,20 @@ from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam as InAppFeedChannelSettingsParam from .guide_activation_location_rule_param import GuideActivationLocationRuleParam as GuideActivationLocationRuleParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam as WorkflowTriggerWorkflowStepParam + +# Rebuild cyclical models only after all modules are imported. +# This ensures that, when building the deferred (due to cyclical references) model schema, +# Pydantic can resolve the necessary references. +# See: https://github.com/pydantic/pydantic/issues/11250 for more context. +if _compat.PYDANTIC_V2: + workflow.Workflow.model_rebuild(_parent_namespace_depth=0) + workflow_branch_step.WorkflowBranchStep.model_rebuild(_parent_namespace_depth=0) + workflow_activate_response.WorkflowActivateResponse.model_rebuild(_parent_namespace_depth=0) + workflow_upsert_response.WorkflowUpsertResponse.model_rebuild(_parent_namespace_depth=0) + workflow_validate_response.WorkflowValidateResponse.model_rebuild(_parent_namespace_depth=0) +else: + workflow.Workflow.update_forward_refs() # type: ignore + workflow_branch_step.WorkflowBranchStep.update_forward_refs() # type: ignore + workflow_activate_response.WorkflowActivateResponse.update_forward_refs() # type: ignore + workflow_upsert_response.WorkflowUpsertResponse.update_forward_refs() # type: ignore + workflow_validate_response.WorkflowValidateResponse.update_forward_refs() # type: ignore diff --git a/src/knock_mapi/types/workflow.py b/src/knock_mapi/types/workflow.py index 25b2a92..3048969 100644 --- a/src/knock_mapi/types/workflow.py +++ b/src/knock_mapi/types/workflow.py @@ -6,7 +6,6 @@ from datetime import datetime from typing_extensions import Literal -from .._compat import PYDANTIC_V2 from .._models import BaseModel from .condition_group import ConditionGroup @@ -101,10 +100,3 @@ class Workflow(BaseModel): from .workflow_step import WorkflowStep - -if PYDANTIC_V2: - Workflow.model_rebuild() - Settings.model_rebuild() -else: - Workflow.update_forward_refs() # type: ignore - Settings.update_forward_refs() # type: ignore diff --git a/src/knock_mapi/types/workflow_activate_response.py b/src/knock_mapi/types/workflow_activate_response.py index dc6c7ec..77b68da 100644 --- a/src/knock_mapi/types/workflow_activate_response.py +++ b/src/knock_mapi/types/workflow_activate_response.py @@ -2,7 +2,6 @@ from __future__ import annotations -from .._compat import PYDANTIC_V2 from .._models import BaseModel __all__ = ["WorkflowActivateResponse"] @@ -14,8 +13,3 @@ class WorkflowActivateResponse(BaseModel): from .workflow import Workflow - -if PYDANTIC_V2: - WorkflowActivateResponse.model_rebuild() -else: - WorkflowActivateResponse.update_forward_refs() # type: ignore diff --git a/src/knock_mapi/types/workflow_branch_step.py b/src/knock_mapi/types/workflow_branch_step.py index b563ff0..273d762 100644 --- a/src/knock_mapi/types/workflow_branch_step.py +++ b/src/knock_mapi/types/workflow_branch_step.py @@ -5,7 +5,6 @@ from typing import List, Optional from typing_extensions import Literal -from .._compat import PYDANTIC_V2 from .._models import BaseModel from .condition_group import ConditionGroup @@ -47,10 +46,3 @@ class WorkflowBranchStep(BaseModel): from .workflow_step import WorkflowStep - -if PYDANTIC_V2: - WorkflowBranchStep.model_rebuild() - Branch.model_rebuild() -else: - WorkflowBranchStep.update_forward_refs() # type: ignore - Branch.update_forward_refs() # type: ignore diff --git a/src/knock_mapi/types/workflow_upsert_response.py b/src/knock_mapi/types/workflow_upsert_response.py index f7bea7c..ccd4945 100644 --- a/src/knock_mapi/types/workflow_upsert_response.py +++ b/src/knock_mapi/types/workflow_upsert_response.py @@ -2,7 +2,6 @@ from __future__ import annotations -from .._compat import PYDANTIC_V2 from .._models import BaseModel __all__ = ["WorkflowUpsertResponse"] @@ -14,8 +13,3 @@ class WorkflowUpsertResponse(BaseModel): from .workflow import Workflow - -if PYDANTIC_V2: - WorkflowUpsertResponse.model_rebuild() -else: - WorkflowUpsertResponse.update_forward_refs() # type: ignore diff --git a/src/knock_mapi/types/workflow_validate_response.py b/src/knock_mapi/types/workflow_validate_response.py index f494e9b..52c20cb 100644 --- a/src/knock_mapi/types/workflow_validate_response.py +++ b/src/knock_mapi/types/workflow_validate_response.py @@ -2,7 +2,6 @@ from __future__ import annotations -from .._compat import PYDANTIC_V2 from .._models import BaseModel __all__ = ["WorkflowValidateResponse"] @@ -14,8 +13,3 @@ class WorkflowValidateResponse(BaseModel): from .workflow import Workflow - -if PYDANTIC_V2: - WorkflowValidateResponse.model_rebuild() -else: - WorkflowValidateResponse.update_forward_refs() # type: ignore From 3d7feb907fb15da8046849fd2bbfbb4f714ee0a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 22 Jul 2025 19:00:44 +0000 Subject: [PATCH 039/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/_models.py | 25 +++++++++++++++++++++++-- tests/test_models.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 413cb0a..76e0012 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-2cb35d96ed42e88afa277ecac1af19c7602e0c4c51103273488f76b249ccbafc.yml -openapi_spec_hash: 0ce501bc5d851779fe26a53bcd81478b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e3ba251959cf45caea32ab451a7e848a91441902184fca8fbecc59b0e1858725.yml +openapi_spec_hash: 2ba9e807202fd4b970436522f1c1823e config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index ffcbf67..b8387ce 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -208,14 +208,18 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] else: fields_values[name] = field_get_default(field) + extra_field_type = _get_extra_fields_type(__cls) + _extra = {} for key, value in values.items(): if key not in model_fields: + parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value + if PYDANTIC_V2: - _extra[key] = value + _extra[key] = parsed else: _fields_set.add(key) - fields_values[key] = value + fields_values[key] = parsed object.__setattr__(m, "__dict__", fields_values) @@ -370,6 +374,23 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) +def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: + if not PYDANTIC_V2: + # TODO + return None + + schema = cls.__pydantic_core_schema__ + if schema["type"] == "model": + fields = schema["schema"] + if fields["type"] == "model-fields": + extras = fields.get("extras_schema") + if extras and "cls" in extras: + # mypy can't narrow the type + return extras["cls"] # type: ignore[no-any-return] + + return None + + def is_basemodel(type_: type) -> bool: """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" if is_union(type_): diff --git a/tests/test_models.py b/tests/test_models.py index d662e08..6fb121f 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,5 +1,5 @@ import json -from typing import Any, Dict, List, Union, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast from datetime import datetime, timezone from typing_extensions import Literal, Annotated, TypeAliasType @@ -934,3 +934,30 @@ class Type2(BaseModel): ) assert isinstance(model, Type1) assert isinstance(model.value, InnerType2) + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="this is only supported in pydantic v2 for now") +def test_extra_properties() -> None: + class Item(BaseModel): + prop: int + + class Model(BaseModel): + __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + other: str + + if TYPE_CHECKING: + + def __getattr__(self, attr: str) -> Item: ... + + model = construct_type( + type_=Model, + value={ + "a": {"prop": 1}, + "other": "foo", + }, + ) + assert isinstance(model, Model) + assert model.a.prop == 1 + assert isinstance(model.a, Item) + assert model.other == "foo" From 07b0bf9ef7044d022823c67bbee43de5ecde93e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:01:57 +0000 Subject: [PATCH 040/101] feat(api): api update --- .gitignore | 1 - .vscode/settings.json | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 8779740..95ceb18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .prism.log -.vscode _dev __pycache__ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5b01030 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.importFormat": "relative", +} From 21c2b12a5d87b3987f8fff6859993f2054c44b3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 20:14:20 +0000 Subject: [PATCH 041/101] feat(api): api update --- src/knock_mapi/_base_client.py | 5 ++++- src/knock_mapi/_files.py | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index be0561e..d5c6132 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -532,7 +532,10 @@ def _build_request( is_body_allowed = options.method.lower() != "get" if is_body_allowed: - kwargs["json"] = json_data if is_given(json_data) else None + if isinstance(json_data, bytes): + kwargs["content"] = json_data + else: + kwargs["json"] = json_data if is_given(json_data) else None kwargs["files"] = files else: headers.pop("Content-Type", None) diff --git a/src/knock_mapi/_files.py b/src/knock_mapi/_files.py index 715cc20..cc14c14 100644 --- a/src/knock_mapi/_files.py +++ b/src/knock_mapi/_files.py @@ -69,12 +69,12 @@ def _transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], _read_file_content(file[1]), *file[2:]) + return (file[0], read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -def _read_file_content(file: FileContent) -> HttpxFileContent: +def read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return pathlib.Path(file).read_bytes() return file @@ -111,12 +111,12 @@ async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: return file if is_tuple_t(file): - return (file[0], await _async_read_file_content(file[1]), *file[2:]) + return (file[0], await async_read_file_content(file[1]), *file[2:]) raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") -async def _async_read_file_content(file: FileContent) -> HttpxFileContent: +async def async_read_file_content(file: FileContent) -> HttpxFileContent: if isinstance(file, os.PathLike): return await anyio.Path(file).read_bytes() From 3cc26f16ba95884a10f9fa8669ca9851d0894847 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 18:51:18 +0000 Subject: [PATCH 042/101] feat(api): api update --- tests/api_resources/test_workflows.py | 340 ++------------------------ 1 file changed, 20 insertions(+), 320 deletions(-) diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 7da3348..b28859f 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -291,14 +291,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) @@ -313,54 +306,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": { - "markdown_body": "Hello **{{ recipient.name }}**", - "action_buttons": [ - { - "action": "https://example.com", - "label": "Button 1", - } - ], - "action_url": "{{ vars.app_url }}", - }, - "type": "channel", - "channel_group_key": "email", - "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, - "conditions": { - "all": [ - { - "operator": "equal_to", - "variable": "recipient.property", - "argument": "some_property", - } - ] - }, - "description": "Delay for 10 seconds", - "send_windows": [ - { - "day": "monday", - "type": "send", - "from": "from", - "until": "until", - } - ], - } - ], + "steps": [], "categories": ["string"], "conditions": { "all": [ @@ -395,14 +341,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -421,14 +360,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) as response: assert not response.is_closed @@ -450,14 +382,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -471,14 +396,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) @@ -493,54 +411,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": { - "markdown_body": "Hello **{{ recipient.name }}**", - "action_buttons": [ - { - "action": "https://example.com", - "label": "Button 1", - } - ], - "action_url": "{{ vars.app_url }}", - }, - "type": "channel", - "channel_group_key": "email", - "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, - "conditions": { - "all": [ - { - "operator": "equal_to", - "variable": "recipient.property", - "argument": "some_property", - } - ] - }, - "description": "Delay for 10 seconds", - "send_windows": [ - { - "day": "monday", - "type": "send", - "from": "from", - "until": "until", - } - ], - } - ], + "steps": [], "categories": ["string"], "conditions": { "all": [ @@ -572,14 +443,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -598,14 +462,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) as response: assert not response.is_closed @@ -627,14 +484,7 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -911,14 +761,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) @@ -933,54 +776,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": { - "markdown_body": "Hello **{{ recipient.name }}**", - "action_buttons": [ - { - "action": "https://example.com", - "label": "Button 1", - } - ], - "action_url": "{{ vars.app_url }}", - }, - "type": "channel", - "channel_group_key": "email", - "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, - "conditions": { - "all": [ - { - "operator": "equal_to", - "variable": "recipient.property", - "argument": "some_property", - } - ] - }, - "description": "Delay for 10 seconds", - "send_windows": [ - { - "day": "monday", - "type": "send", - "from": "from", - "until": "until", - } - ], - } - ], + "steps": [], "categories": ["string"], "conditions": { "all": [ @@ -1015,14 +811,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -1041,14 +830,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) as response: assert not response.is_closed @@ -1070,14 +852,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -1091,14 +866,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) @@ -1113,54 +881,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": { - "markdown_body": "Hello **{{ recipient.name }}**", - "action_buttons": [ - { - "action": "https://example.com", - "label": "Button 1", - } - ], - "action_url": "{{ vars.app_url }}", - }, - "type": "channel", - "channel_group_key": "email", - "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, - "conditions": { - "all": [ - { - "operator": "equal_to", - "variable": "recipient.property", - "argument": "some_property", - } - ] - }, - "description": "Delay for 10 seconds", - "send_windows": [ - { - "day": "monday", - "type": "send", - "from": "from", - "until": "until", - } - ], - } - ], + "steps": [], "categories": ["string"], "conditions": { "all": [ @@ -1192,14 +913,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) @@ -1218,14 +932,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) as response: assert not response.is_closed @@ -1247,13 +954,6 @@ async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [ - { - "name": "Channel 1", - "ref": "channel_1", - "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, - "type": "channel", - } - ], + "steps": [], }, ) From 0cad2fb280ed744324ded81614829bc683e68a14 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:24:43 +0000 Subject: [PATCH 043/101] feat(api): api update --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ac40ca0..df413bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -159,7 +159,7 @@ reportPrivateUsage = false [tool.ruff] line-length = 120 output-format = "grouped" -target-version = "py37" +target-version = "py38" [tool.ruff.format] docstring-code-format = true From bc2a719d1aa7fad4194e872ca1c3240c1c042f3f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 18:33:38 +0000 Subject: [PATCH 044/101] feat(api): api update --- scripts/mock | 4 +- scripts/test | 2 +- tests/api_resources/test_api_keys.py | 24 +-- tests/api_resources/test_auth.py | 24 +-- tests/api_resources/test_channel_groups.py | 32 +-- tests/api_resources/test_channels.py | 32 +-- tests/api_resources/test_commits.py | 152 ++++--------- tests/api_resources/test_email_layouts.py | 152 ++++--------- tests/api_resources/test_environments.py | 64 ++---- tests/api_resources/test_guides.py | 224 +++++--------------- tests/api_resources/test_message_types.py | 152 ++++--------- tests/api_resources/test_partials.py | 152 ++++--------- tests/api_resources/test_translations.py | 144 ++++--------- tests/api_resources/test_variables.py | 32 +-- tests/api_resources/test_workflows.py | 224 +++++--------------- tests/api_resources/workflows/test_steps.py | 40 +--- 16 files changed, 365 insertions(+), 1089 deletions(-) diff --git a/scripts/mock b/scripts/mock index d2814ae..0b28f6e 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & # Wait for server to come online echo -n "Waiting for server" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi diff --git a/scripts/test b/scripts/test index 2b87845..dbeda2d 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then 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=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 diff --git a/tests/api_resources/test_api_keys.py b/tests/api_resources/test_api_keys.py index 08011b3..a75cd36 100644 --- a/tests/api_resources/test_api_keys.py +++ b/tests/api_resources/test_api_keys.py @@ -17,9 +17,7 @@ class TestAPIKeys: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_exchange(self, client: KnockMgmt) -> None: api_key = client.api_keys.exchange( @@ -27,9 +25,7 @@ def test_method_exchange(self, client: KnockMgmt) -> None: ) assert_matches_type(APIKeyExchangeResponse, api_key, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_exchange(self, client: KnockMgmt) -> None: response = client.api_keys.with_raw_response.exchange( @@ -41,9 +37,7 @@ def test_raw_response_exchange(self, client: KnockMgmt) -> None: api_key = response.parse() assert_matches_type(APIKeyExchangeResponse, api_key, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_exchange(self, client: KnockMgmt) -> None: with client.api_keys.with_streaming_response.exchange( @@ -63,9 +57,7 @@ class TestAsyncAPIKeys: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_exchange(self, async_client: AsyncKnockMgmt) -> None: api_key = await async_client.api_keys.exchange( @@ -73,9 +65,7 @@ async def test_method_exchange(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(APIKeyExchangeResponse, api_key, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_exchange(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.api_keys.with_raw_response.exchange( @@ -87,9 +77,7 @@ async def test_raw_response_exchange(self, async_client: AsyncKnockMgmt) -> None api_key = await response.parse() assert_matches_type(APIKeyExchangeResponse, api_key, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_exchange(self, async_client: AsyncKnockMgmt) -> None: async with async_client.api_keys.with_streaming_response.exchange( diff --git a/tests/api_resources/test_auth.py b/tests/api_resources/test_auth.py index f10cb0d..aad95d2 100644 --- a/tests/api_resources/test_auth.py +++ b/tests/api_resources/test_auth.py @@ -17,17 +17,13 @@ class TestAuth: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_verify(self, client: KnockMgmt) -> None: auth = client.auth.verify() assert_matches_type(AuthVerifyResponse, auth, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_verify(self, client: KnockMgmt) -> None: response = client.auth.with_raw_response.verify() @@ -37,9 +33,7 @@ def test_raw_response_verify(self, client: KnockMgmt) -> None: auth = response.parse() assert_matches_type(AuthVerifyResponse, auth, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_verify(self, client: KnockMgmt) -> None: with client.auth.with_streaming_response.verify() as response: @@ -57,17 +51,13 @@ class TestAsyncAuth: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_verify(self, async_client: AsyncKnockMgmt) -> None: auth = await async_client.auth.verify() assert_matches_type(AuthVerifyResponse, auth, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_verify(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.auth.with_raw_response.verify() @@ -77,9 +67,7 @@ async def test_raw_response_verify(self, async_client: AsyncKnockMgmt) -> None: auth = await response.parse() assert_matches_type(AuthVerifyResponse, auth, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_verify(self, async_client: AsyncKnockMgmt) -> None: async with async_client.auth.with_streaming_response.verify() as response: diff --git a/tests/api_resources/test_channel_groups.py b/tests/api_resources/test_channel_groups.py index 1f344c5..503fef9 100644 --- a/tests/api_resources/test_channel_groups.py +++ b/tests/api_resources/test_channel_groups.py @@ -18,17 +18,13 @@ class TestChannelGroups: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: channel_group = client.channel_groups.list() assert_matches_type(SyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: channel_group = client.channel_groups.list( @@ -38,9 +34,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.channel_groups.with_raw_response.list() @@ -50,9 +44,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: channel_group = response.parse() assert_matches_type(SyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.channel_groups.with_streaming_response.list() as response: @@ -70,17 +62,13 @@ class TestAsyncChannelGroups: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: channel_group = await async_client.channel_groups.list() assert_matches_type(AsyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: channel_group = await async_client.channel_groups.list( @@ -90,9 +78,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.channel_groups.with_raw_response.list() @@ -102,9 +88,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: channel_group = await response.parse() assert_matches_type(AsyncEntriesCursor[ChannelGroup], channel_group, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.channel_groups.with_streaming_response.list() as response: diff --git a/tests/api_resources/test_channels.py b/tests/api_resources/test_channels.py index a8ece50..2bbbc80 100644 --- a/tests/api_resources/test_channels.py +++ b/tests/api_resources/test_channels.py @@ -18,17 +18,13 @@ class TestChannels: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: channel = client.channels.list() assert_matches_type(SyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: channel = client.channels.list( @@ -38,9 +34,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.channels.with_raw_response.list() @@ -50,9 +44,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: channel = response.parse() assert_matches_type(SyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.channels.with_streaming_response.list() as response: @@ -70,17 +62,13 @@ class TestAsyncChannels: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: channel = await async_client.channels.list() assert_matches_type(AsyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: channel = await async_client.channels.list( @@ -90,9 +78,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.channels.with_raw_response.list() @@ -102,9 +88,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: channel = await response.parse() assert_matches_type(AsyncEntriesCursor[Channel], channel, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.channels.with_streaming_response.list() as response: diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 8649cb3..06167e5 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -23,9 +23,7 @@ class TestCommits: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: commit = client.commits.retrieve( @@ -33,9 +31,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(Commit, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.commits.with_raw_response.retrieve( @@ -47,9 +43,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: commit = response.parse() assert_matches_type(Commit, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.commits.with_streaming_response.retrieve( @@ -63,9 +57,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): @@ -73,9 +65,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: "", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: commit = client.commits.list( @@ -83,9 +73,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: commit = client.commits.list( @@ -97,9 +85,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.commits.with_raw_response.list( @@ -111,9 +97,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: commit = response.parse() assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.commits.with_streaming_response.list( @@ -127,9 +111,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_commit_all(self, client: KnockMgmt) -> None: commit = client.commits.commit_all( @@ -137,9 +119,7 @@ def test_method_commit_all(self, client: KnockMgmt) -> None: ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_commit_all_with_all_params(self, client: KnockMgmt) -> None: commit = client.commits.commit_all( @@ -148,9 +128,7 @@ def test_method_commit_all_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_commit_all(self, client: KnockMgmt) -> None: response = client.commits.with_raw_response.commit_all( @@ -162,9 +140,7 @@ def test_raw_response_commit_all(self, client: KnockMgmt) -> None: commit = response.parse() assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_commit_all(self, client: KnockMgmt) -> None: with client.commits.with_streaming_response.commit_all( @@ -178,9 +154,7 @@ def test_streaming_response_commit_all(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_promote_all(self, client: KnockMgmt) -> None: commit = client.commits.promote_all( @@ -188,9 +162,7 @@ def test_method_promote_all(self, client: KnockMgmt) -> None: ) assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_promote_all(self, client: KnockMgmt) -> None: response = client.commits.with_raw_response.promote_all( @@ -202,9 +174,7 @@ def test_raw_response_promote_all(self, client: KnockMgmt) -> None: commit = response.parse() assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_promote_all(self, client: KnockMgmt) -> None: with client.commits.with_streaming_response.promote_all( @@ -218,9 +188,7 @@ def test_streaming_response_promote_all(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_promote_one(self, client: KnockMgmt) -> None: commit = client.commits.promote_one( @@ -228,9 +196,7 @@ def test_method_promote_one(self, client: KnockMgmt) -> None: ) assert_matches_type(CommitPromoteOneResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_promote_one(self, client: KnockMgmt) -> None: response = client.commits.with_raw_response.promote_one( @@ -242,9 +208,7 @@ def test_raw_response_promote_one(self, client: KnockMgmt) -> None: commit = response.parse() assert_matches_type(CommitPromoteOneResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_promote_one(self, client: KnockMgmt) -> None: with client.commits.with_streaming_response.promote_one( @@ -258,9 +222,7 @@ def test_streaming_response_promote_one(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_promote_one(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): @@ -274,9 +236,7 @@ class TestAsyncCommits: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.retrieve( @@ -284,9 +244,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(Commit, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.commits.with_raw_response.retrieve( @@ -298,9 +256,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None commit = await response.parse() assert_matches_type(Commit, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.commits.with_streaming_response.retrieve( @@ -314,9 +270,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): @@ -324,9 +278,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: "", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.list( @@ -334,9 +286,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.list( @@ -348,9 +298,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.commits.with_raw_response.list( @@ -362,9 +310,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: commit = await response.parse() assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.commits.with_streaming_response.list( @@ -378,9 +324,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_commit_all(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.commit_all( @@ -388,9 +332,7 @@ async def test_method_commit_all(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_commit_all_with_all_params(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.commit_all( @@ -399,9 +341,7 @@ async def test_method_commit_all_with_all_params(self, async_client: AsyncKnockM ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_commit_all(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.commits.with_raw_response.commit_all( @@ -413,9 +353,7 @@ async def test_raw_response_commit_all(self, async_client: AsyncKnockMgmt) -> No commit = await response.parse() assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_commit_all(self, async_client: AsyncKnockMgmt) -> None: async with async_client.commits.with_streaming_response.commit_all( @@ -429,9 +367,7 @@ async def test_streaming_response_commit_all(self, async_client: AsyncKnockMgmt) assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_promote_all(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.promote_all( @@ -439,9 +375,7 @@ async def test_method_promote_all(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_promote_all(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.commits.with_raw_response.promote_all( @@ -453,9 +387,7 @@ async def test_raw_response_promote_all(self, async_client: AsyncKnockMgmt) -> N commit = await response.parse() assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_promote_all(self, async_client: AsyncKnockMgmt) -> None: async with async_client.commits.with_streaming_response.promote_all( @@ -469,9 +401,7 @@ async def test_streaming_response_promote_all(self, async_client: AsyncKnockMgmt assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_promote_one(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.promote_one( @@ -479,9 +409,7 @@ async def test_method_promote_one(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(CommitPromoteOneResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_promote_one(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.commits.with_raw_response.promote_one( @@ -493,9 +421,7 @@ async def test_raw_response_promote_one(self, async_client: AsyncKnockMgmt) -> N commit = await response.parse() assert_matches_type(CommitPromoteOneResponse, commit, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_promote_one(self, async_client: AsyncKnockMgmt) -> None: async with async_client.commits.with_streaming_response.promote_one( @@ -509,9 +435,7 @@ async def test_streaming_response_promote_one(self, async_client: AsyncKnockMgmt assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_promote_one(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): diff --git a/tests/api_resources/test_email_layouts.py b/tests/api_resources/test_email_layouts.py index 3b25c70..ab47629 100644 --- a/tests/api_resources/test_email_layouts.py +++ b/tests/api_resources/test_email_layouts.py @@ -22,9 +22,7 @@ class TestEmailLayouts: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.retrieve( @@ -33,9 +31,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.retrieve( @@ -46,9 +42,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.email_layouts.with_raw_response.retrieve( @@ -61,9 +55,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: email_layout = response.parse() assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.email_layouts.with_streaming_response.retrieve( @@ -78,9 +70,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): @@ -89,9 +79,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.list( @@ -99,9 +87,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.list( @@ -114,9 +100,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.email_layouts.with_raw_response.list( @@ -128,9 +112,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: email_layout = response.parse() assert_matches_type(SyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.email_layouts.with_streaming_response.list( @@ -144,9 +126,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.upsert( @@ -160,9 +140,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.upsert( @@ -185,9 +163,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.email_layouts.with_raw_response.upsert( @@ -205,9 +181,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: email_layout = response.parse() assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.email_layouts.with_streaming_response.upsert( @@ -227,9 +201,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): @@ -243,9 +215,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.validate( @@ -259,9 +229,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: email_layout = client.email_layouts.validate( @@ -281,9 +249,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.email_layouts.with_raw_response.validate( @@ -301,9 +267,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: email_layout = response.parse() assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.email_layouts.with_streaming_response.validate( @@ -323,9 +287,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): @@ -345,9 +307,7 @@ class TestAsyncEmailLayouts: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.retrieve( @@ -356,9 +316,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.retrieve( @@ -369,9 +327,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.email_layouts.with_raw_response.retrieve( @@ -384,9 +340,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None email_layout = await response.parse() assert_matches_type(EmailLayout, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.email_layouts.with_streaming_response.retrieve( @@ -401,9 +355,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): @@ -412,9 +364,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.list( @@ -422,9 +372,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.list( @@ -437,9 +385,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.email_layouts.with_raw_response.list( @@ -451,9 +397,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: email_layout = await response.parse() assert_matches_type(AsyncEntriesCursor[EmailLayout], email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.email_layouts.with_streaming_response.list( @@ -467,9 +411,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.upsert( @@ -483,9 +425,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.upsert( @@ -508,9 +448,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.email_layouts.with_raw_response.upsert( @@ -528,9 +466,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: email_layout = await response.parse() assert_matches_type(EmailLayoutUpsertResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.email_layouts.with_streaming_response.upsert( @@ -550,9 +486,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): @@ -566,9 +500,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.validate( @@ -582,9 +514,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: email_layout = await async_client.email_layouts.validate( @@ -604,9 +534,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.email_layouts.with_raw_response.validate( @@ -624,9 +552,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None email_layout = await response.parse() assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.email_layouts.with_streaming_response.validate( @@ -646,9 +572,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `email_layout_key` but received ''"): diff --git a/tests/api_resources/test_environments.py b/tests/api_resources/test_environments.py index cd00196..09366f7 100644 --- a/tests/api_resources/test_environments.py +++ b/tests/api_resources/test_environments.py @@ -18,9 +18,7 @@ class TestEnvironments: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: environment = client.environments.retrieve( @@ -28,9 +26,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(Environment, environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.environments.with_raw_response.retrieve( @@ -42,9 +38,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: environment = response.parse() assert_matches_type(Environment, environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.environments.with_streaming_response.retrieve( @@ -58,9 +52,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `environment_slug` but received ''"): @@ -68,17 +60,13 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: "", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: environment = client.environments.list() assert_matches_type(SyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: environment = client.environments.list( @@ -88,9 +76,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.environments.with_raw_response.list() @@ -100,9 +86,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: environment = response.parse() assert_matches_type(SyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.environments.with_streaming_response.list() as response: @@ -120,9 +104,7 @@ class TestAsyncEnvironments: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment = await async_client.environments.retrieve( @@ -130,9 +112,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(Environment, environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.environments.with_raw_response.retrieve( @@ -144,9 +124,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None environment = await response.parse() assert_matches_type(Environment, environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.environments.with_streaming_response.retrieve( @@ -160,9 +138,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `environment_slug` but received ''"): @@ -170,17 +146,13 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: "", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: environment = await async_client.environments.list() assert_matches_type(AsyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: environment = await async_client.environments.list( @@ -190,9 +162,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.environments.with_raw_response.list() @@ -202,9 +172,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: environment = await response.parse() assert_matches_type(AsyncEntriesCursor[Environment], environment, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.environments.with_streaming_response.list() as response: diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index 2c00570..b0aaf64 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -24,9 +24,7 @@ class TestGuides: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: guide = client.guides.retrieve( @@ -35,9 +33,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: guide = client.guides.retrieve( @@ -48,9 +44,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.retrieve( @@ -63,9 +57,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.retrieve( @@ -80,9 +72,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -91,9 +81,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: guide = client.guides.list( @@ -101,9 +89,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: guide = client.guides.list( @@ -116,9 +102,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.list( @@ -130,9 +114,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.list( @@ -146,9 +128,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_activate_overload_1(self, client: KnockMgmt) -> None: guide = client.guides.activate( @@ -158,9 +138,7 @@ def test_method_activate_overload_1(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_activate_overload_1(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.activate( @@ -174,9 +152,7 @@ def test_raw_response_activate_overload_1(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_activate_overload_1(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.activate( @@ -192,9 +168,7 @@ def test_streaming_response_activate_overload_1(self, client: KnockMgmt) -> None assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_activate_overload_1(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -204,9 +178,7 @@ def test_path_params_activate_overload_1(self, client: KnockMgmt) -> None: status=True, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_activate_overload_2(self, client: KnockMgmt) -> None: guide = client.guides.activate( @@ -215,9 +187,7 @@ def test_method_activate_overload_2(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_activate_with_all_params_overload_2(self, client: KnockMgmt) -> None: guide = client.guides.activate( @@ -228,9 +198,7 @@ def test_method_activate_with_all_params_overload_2(self, client: KnockMgmt) -> ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_activate_overload_2(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.activate( @@ -243,9 +211,7 @@ def test_raw_response_activate_overload_2(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_activate_overload_2(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.activate( @@ -260,9 +226,7 @@ def test_streaming_response_activate_overload_2(self, client: KnockMgmt) -> None assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_activate_overload_2(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -271,9 +235,7 @@ def test_path_params_activate_overload_2(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: guide = client.guides.upsert( @@ -294,9 +256,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: guide = client.guides.upsert( @@ -341,9 +301,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.upsert( @@ -368,9 +326,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.upsert( @@ -397,9 +353,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -420,9 +374,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: guide = client.guides.validate( @@ -443,9 +395,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: guide = client.guides.validate( @@ -487,9 +437,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.guides.with_raw_response.validate( @@ -514,9 +462,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: guide = response.parse() assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.guides.with_streaming_response.validate( @@ -543,9 +489,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -572,9 +516,7 @@ class TestAsyncGuides: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.retrieve( @@ -583,9 +525,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.retrieve( @@ -596,9 +536,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.retrieve( @@ -611,9 +549,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None guide = await response.parse() assert_matches_type(Guide, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.retrieve( @@ -628,9 +564,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -639,9 +573,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.list( @@ -649,9 +581,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.list( @@ -664,9 +594,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.list( @@ -678,9 +606,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: guide = await response.parse() assert_matches_type(AsyncEntriesCursor[Guide], guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.list( @@ -694,9 +620,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.activate( @@ -706,9 +630,7 @@ async def test_method_activate_overload_1(self, async_client: AsyncKnockMgmt) -> ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.activate( @@ -722,9 +644,7 @@ async def test_raw_response_activate_overload_1(self, async_client: AsyncKnockMg guide = await response.parse() assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.activate( @@ -740,9 +660,7 @@ async def test_streaming_response_activate_overload_1(self, async_client: AsyncK assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -752,9 +670,7 @@ async def test_path_params_activate_overload_1(self, async_client: AsyncKnockMgm status=True, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.activate( @@ -763,9 +679,7 @@ async def test_method_activate_overload_2(self, async_client: AsyncKnockMgmt) -> ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_activate_with_all_params_overload_2(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.activate( @@ -776,9 +690,7 @@ async def test_method_activate_with_all_params_overload_2(self, async_client: As ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.activate( @@ -791,9 +703,7 @@ async def test_raw_response_activate_overload_2(self, async_client: AsyncKnockMg guide = await response.parse() assert_matches_type(GuideActivateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.activate( @@ -808,9 +718,7 @@ async def test_streaming_response_activate_overload_2(self, async_client: AsyncK assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_activate_overload_2(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -819,9 +727,7 @@ async def test_path_params_activate_overload_2(self, async_client: AsyncKnockMgm environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.upsert( @@ -842,9 +748,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.upsert( @@ -889,9 +793,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.upsert( @@ -916,9 +818,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: guide = await response.parse() assert_matches_type(GuideUpsertResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.upsert( @@ -945,9 +845,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): @@ -968,9 +866,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.validate( @@ -991,9 +887,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: guide = await async_client.guides.validate( @@ -1035,9 +929,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.guides.with_raw_response.validate( @@ -1062,9 +954,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None guide = await response.parse() assert_matches_type(GuideValidateResponse, guide, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.guides.with_streaming_response.validate( @@ -1091,9 +981,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): diff --git a/tests/api_resources/test_message_types.py b/tests/api_resources/test_message_types.py index df8b405..7cf1bbd 100644 --- a/tests/api_resources/test_message_types.py +++ b/tests/api_resources/test_message_types.py @@ -22,9 +22,7 @@ class TestMessageTypes: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: message_type = client.message_types.retrieve( @@ -33,9 +31,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: message_type = client.message_types.retrieve( @@ -46,9 +42,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.message_types.with_raw_response.retrieve( @@ -61,9 +55,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: message_type = response.parse() assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.message_types.with_streaming_response.retrieve( @@ -78,9 +70,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): @@ -89,9 +79,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: message_type = client.message_types.list( @@ -99,9 +87,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: message_type = client.message_types.list( @@ -114,9 +100,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.message_types.with_raw_response.list( @@ -128,9 +112,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: message_type = response.parse() assert_matches_type(SyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.message_types.with_streaming_response.list( @@ -144,9 +126,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: message_type = client.message_types.upsert( @@ -160,9 +140,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: message_type = client.message_types.upsert( @@ -201,9 +179,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.message_types.with_raw_response.upsert( @@ -221,9 +197,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: message_type = response.parse() assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.message_types.with_streaming_response.upsert( @@ -243,9 +217,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): @@ -259,9 +231,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: message_type = client.message_types.validate( @@ -275,9 +245,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: message_type = client.message_types.validate( @@ -313,9 +281,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.message_types.with_raw_response.validate( @@ -333,9 +299,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: message_type = response.parse() assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.message_types.with_streaming_response.validate( @@ -355,9 +319,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): @@ -377,9 +339,7 @@ class TestAsyncMessageTypes: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.retrieve( @@ -388,9 +348,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.retrieve( @@ -401,9 +359,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.message_types.with_raw_response.retrieve( @@ -416,9 +372,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None message_type = await response.parse() assert_matches_type(MessageType, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.message_types.with_streaming_response.retrieve( @@ -433,9 +387,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): @@ -444,9 +396,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.list( @@ -454,9 +404,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.list( @@ -469,9 +417,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.message_types.with_raw_response.list( @@ -483,9 +429,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: message_type = await response.parse() assert_matches_type(AsyncEntriesCursor[MessageType], message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.message_types.with_streaming_response.list( @@ -499,9 +443,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.upsert( @@ -515,9 +457,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.upsert( @@ -556,9 +496,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.message_types.with_raw_response.upsert( @@ -576,9 +514,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: message_type = await response.parse() assert_matches_type(MessageTypeUpsertResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.message_types.with_streaming_response.upsert( @@ -598,9 +534,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): @@ -614,9 +548,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.validate( @@ -630,9 +562,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: message_type = await async_client.message_types.validate( @@ -668,9 +598,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.message_types.with_raw_response.validate( @@ -688,9 +616,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None message_type = await response.parse() assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.message_types.with_streaming_response.validate( @@ -710,9 +636,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `message_type_key` but received ''"): diff --git a/tests/api_resources/test_partials.py b/tests/api_resources/test_partials.py index 44a498d..230aeea 100644 --- a/tests/api_resources/test_partials.py +++ b/tests/api_resources/test_partials.py @@ -22,9 +22,7 @@ class TestPartials: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: partial = client.partials.retrieve( @@ -33,9 +31,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: partial = client.partials.retrieve( @@ -46,9 +42,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.partials.with_raw_response.retrieve( @@ -61,9 +55,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: partial = response.parse() assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.partials.with_streaming_response.retrieve( @@ -78,9 +70,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): @@ -89,9 +79,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: partial = client.partials.list( @@ -99,9 +87,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: partial = client.partials.list( @@ -114,9 +100,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.partials.with_raw_response.list( @@ -128,9 +112,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: partial = response.parse() assert_matches_type(SyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.partials.with_streaming_response.list( @@ -144,9 +126,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: partial = client.partials.upsert( @@ -160,9 +140,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: partial = client.partials.upsert( @@ -182,9 +160,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.partials.with_raw_response.upsert( @@ -202,9 +178,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: partial = response.parse() assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.partials.with_streaming_response.upsert( @@ -224,9 +198,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): @@ -240,9 +212,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: partial = client.partials.validate( @@ -256,9 +226,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: partial = client.partials.validate( @@ -275,9 +243,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.partials.with_raw_response.validate( @@ -295,9 +261,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: partial = response.parse() assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.partials.with_streaming_response.validate( @@ -317,9 +281,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): @@ -339,9 +301,7 @@ class TestAsyncPartials: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.retrieve( @@ -350,9 +310,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.retrieve( @@ -363,9 +321,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.partials.with_raw_response.retrieve( @@ -378,9 +334,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None partial = await response.parse() assert_matches_type(Partial, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.partials.with_streaming_response.retrieve( @@ -395,9 +349,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): @@ -406,9 +358,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.list( @@ -416,9 +366,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.list( @@ -431,9 +379,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.partials.with_raw_response.list( @@ -445,9 +391,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: partial = await response.parse() assert_matches_type(AsyncEntriesCursor[Partial], partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.partials.with_streaming_response.list( @@ -461,9 +405,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.upsert( @@ -477,9 +419,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.upsert( @@ -499,9 +439,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.partials.with_raw_response.upsert( @@ -519,9 +457,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: partial = await response.parse() assert_matches_type(PartialUpsertResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.partials.with_streaming_response.upsert( @@ -541,9 +477,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): @@ -557,9 +491,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.validate( @@ -573,9 +505,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: partial = await async_client.partials.validate( @@ -592,9 +522,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.partials.with_raw_response.validate( @@ -612,9 +540,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None partial = await response.parse() assert_matches_type(PartialValidateResponse, partial, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.partials.with_streaming_response.validate( @@ -634,9 +560,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `partial_key` but received ''"): diff --git a/tests/api_resources/test_translations.py b/tests/api_resources/test_translations.py index b68c396..51782ce 100644 --- a/tests/api_resources/test_translations.py +++ b/tests/api_resources/test_translations.py @@ -23,9 +23,7 @@ class TestTranslations: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: translation = client.translations.retrieve( @@ -34,9 +32,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: translation = client.translations.retrieve( @@ -49,9 +45,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.translations.with_raw_response.retrieve( @@ -64,9 +58,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: translation = response.parse() assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.translations.with_streaming_response.retrieve( @@ -81,9 +73,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): @@ -92,9 +82,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: translation = client.translations.list( @@ -102,9 +90,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: translation = client.translations.list( @@ -120,9 +106,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.translations.with_raw_response.list( @@ -134,9 +118,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: translation = response.parse() assert_matches_type(SyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.translations.with_streaming_response.list( @@ -150,9 +132,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: translation = client.translations.upsert( @@ -166,9 +146,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: translation = client.translations.upsert( @@ -186,9 +164,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.translations.with_raw_response.upsert( @@ -206,9 +182,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: translation = response.parse() assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.translations.with_streaming_response.upsert( @@ -228,9 +202,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): @@ -244,9 +216,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: translation = client.translations.validate( @@ -259,9 +229,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationValidateResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.translations.with_raw_response.validate( @@ -278,9 +246,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: translation = response.parse() assert_matches_type(TranslationValidateResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.translations.with_streaming_response.validate( @@ -299,9 +265,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): @@ -320,9 +284,7 @@ class TestAsyncTranslations: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.retrieve( @@ -331,9 +293,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.retrieve( @@ -346,9 +306,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.translations.with_raw_response.retrieve( @@ -361,9 +319,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None translation = await response.parse() assert_matches_type(TranslationRetrieveResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.translations.with_streaming_response.retrieve( @@ -378,9 +334,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): @@ -389,9 +343,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.list( @@ -399,9 +351,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.list( @@ -417,9 +367,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.translations.with_raw_response.list( @@ -431,9 +379,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: translation = await response.parse() assert_matches_type(AsyncEntriesCursor[Translation], translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.translations.with_streaming_response.list( @@ -447,9 +393,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.upsert( @@ -463,9 +407,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.upsert( @@ -483,9 +425,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.translations.with_raw_response.upsert( @@ -503,9 +443,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: translation = await response.parse() assert_matches_type(TranslationUpsertResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.translations.with_streaming_response.upsert( @@ -525,9 +463,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): @@ -541,9 +477,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: translation = await async_client.translations.validate( @@ -556,9 +490,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(TranslationValidateResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.translations.with_raw_response.validate( @@ -575,9 +507,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None translation = await response.parse() assert_matches_type(TranslationValidateResponse, translation, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.translations.with_streaming_response.validate( @@ -596,9 +526,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `locale_code` but received ''"): diff --git a/tests/api_resources/test_variables.py b/tests/api_resources/test_variables.py index 09ec4ea..2e8b340 100644 --- a/tests/api_resources/test_variables.py +++ b/tests/api_resources/test_variables.py @@ -18,9 +18,7 @@ class TestVariables: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: variable = client.variables.list( @@ -28,9 +26,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: variable = client.variables.list( @@ -41,9 +37,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.variables.with_raw_response.list( @@ -55,9 +49,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: variable = response.parse() assert_matches_type(SyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.variables.with_streaming_response.list( @@ -77,9 +69,7 @@ class TestAsyncVariables: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: variable = await async_client.variables.list( @@ -87,9 +77,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: variable = await async_client.variables.list( @@ -100,9 +88,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.variables.with_raw_response.list( @@ -114,9 +100,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: variable = await response.parse() assert_matches_type(AsyncEntriesCursor[Variable], variable, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.variables.with_streaming_response.list( diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index b28859f..2c930ae 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -24,9 +24,7 @@ class TestWorkflows: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve(self, client: KnockMgmt) -> None: workflow = client.workflows.retrieve( @@ -35,9 +33,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: ) assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: workflow = client.workflows.retrieve( @@ -48,9 +44,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_retrieve(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.retrieve( @@ -63,9 +57,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.retrieve( @@ -80,9 +72,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_retrieve(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -91,9 +81,7 @@ def test_path_params_retrieve(self, client: KnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list(self, client: KnockMgmt) -> None: workflow = client.workflows.list( @@ -101,9 +89,7 @@ def test_method_list(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: workflow = client.workflows.list( @@ -116,9 +102,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(SyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_list(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.list( @@ -130,9 +114,7 @@ def test_raw_response_list(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(SyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_list(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.list( @@ -146,9 +128,7 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_activate(self, client: KnockMgmt) -> None: workflow = client.workflows.activate( @@ -158,9 +138,7 @@ def test_method_activate(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_activate(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.activate( @@ -174,9 +152,7 @@ def test_raw_response_activate(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_activate(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.activate( @@ -192,9 +168,7 @@ def test_streaming_response_activate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_activate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -204,9 +178,7 @@ def test_path_params_activate(self, client: KnockMgmt) -> None: status=True, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_run(self, client: KnockMgmt) -> None: workflow = client.workflows.run( @@ -216,9 +188,7 @@ def test_method_run(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_run_with_all_params(self, client: KnockMgmt) -> None: workflow = client.workflows.run( @@ -235,9 +205,7 @@ def test_method_run_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_run(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.run( @@ -251,9 +219,7 @@ def test_raw_response_run(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_run(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.run( @@ -269,9 +235,7 @@ def test_streaming_response_run(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_run(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -281,9 +245,7 @@ def test_path_params_run(self, client: KnockMgmt) -> None: recipients=["dnedry"], ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: workflow = client.workflows.upsert( @@ -296,9 +258,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: workflow = client.workflows.upsert( @@ -331,9 +291,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_upsert(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.upsert( @@ -350,9 +308,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_upsert(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.upsert( @@ -371,9 +327,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_upsert(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -386,9 +340,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate(self, client: KnockMgmt) -> None: workflow = client.workflows.validate( @@ -401,9 +353,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: workflow = client.workflows.validate( @@ -433,9 +383,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: response = client.workflows.with_raw_response.validate( @@ -452,9 +400,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: workflow = response.parse() assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_validate(self, client: KnockMgmt) -> None: with client.workflows.with_streaming_response.validate( @@ -473,9 +419,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_validate(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -494,9 +438,7 @@ class TestAsyncWorkflows: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.retrieve( @@ -505,9 +447,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.retrieve( @@ -518,9 +458,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.retrieve( @@ -533,9 +471,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None workflow = await response.parse() assert_matches_type(Workflow, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.retrieve( @@ -550,9 +486,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -561,9 +495,7 @@ async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: environment="development", ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.list( @@ -571,9 +503,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(AsyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.list( @@ -586,9 +516,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - ) assert_matches_type(AsyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.list( @@ -600,9 +528,7 @@ async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: workflow = await response.parse() assert_matches_type(AsyncEntriesCursor[Workflow], workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.list( @@ -616,9 +542,7 @@ async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> No assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_activate(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.activate( @@ -628,9 +552,7 @@ async def test_method_activate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_activate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.activate( @@ -644,9 +566,7 @@ async def test_raw_response_activate(self, async_client: AsyncKnockMgmt) -> None workflow = await response.parse() assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_activate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.activate( @@ -662,9 +582,7 @@ async def test_streaming_response_activate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_activate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -674,9 +592,7 @@ async def test_path_params_activate(self, async_client: AsyncKnockMgmt) -> None: status=True, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_run(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.run( @@ -686,9 +602,7 @@ async def test_method_run(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_run_with_all_params(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.run( @@ -705,9 +619,7 @@ async def test_method_run_with_all_params(self, async_client: AsyncKnockMgmt) -> ) assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_run(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.run( @@ -721,9 +633,7 @@ async def test_raw_response_run(self, async_client: AsyncKnockMgmt) -> None: workflow = await response.parse() assert_matches_type(WorkflowRunResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_run(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.run( @@ -739,9 +649,7 @@ async def test_streaming_response_run(self, async_client: AsyncKnockMgmt) -> Non assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_run(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -751,9 +659,7 @@ async def test_path_params_run(self, async_client: AsyncKnockMgmt) -> None: recipients=["dnedry"], ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.upsert( @@ -766,9 +672,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.upsert( @@ -801,9 +705,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.upsert( @@ -820,9 +722,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: workflow = await response.parse() assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.upsert( @@ -841,9 +741,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -856,9 +754,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: }, ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.validate( @@ -871,9 +767,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: workflow = await async_client.workflows.validate( @@ -903,9 +797,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.with_raw_response.validate( @@ -922,9 +814,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None workflow = await response.parse() assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.with_streaming_response.validate( @@ -943,9 +833,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): diff --git a/tests/api_resources/workflows/test_steps.py b/tests/api_resources/workflows/test_steps.py index 8dc1c92..74f54ed 100644 --- a/tests/api_resources/workflows/test_steps.py +++ b/tests/api_resources/workflows/test_steps.py @@ -17,9 +17,7 @@ class TestSteps: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_preview_template(self, client: KnockMgmt) -> None: step = client.workflows.steps.preview_template( @@ -30,9 +28,7 @@ def test_method_preview_template(self, client: KnockMgmt) -> None: ) assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_preview_template_with_all_params(self, client: KnockMgmt) -> None: step = client.workflows.steps.preview_template( @@ -46,9 +42,7 @@ def test_method_preview_template_with_all_params(self, client: KnockMgmt) -> Non ) assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_preview_template(self, client: KnockMgmt) -> None: response = client.workflows.steps.with_raw_response.preview_template( @@ -63,9 +57,7 @@ def test_raw_response_preview_template(self, client: KnockMgmt) -> None: step = response.parse() assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_streaming_response_preview_template(self, client: KnockMgmt) -> None: with client.workflows.steps.with_streaming_response.preview_template( @@ -82,9 +74,7 @@ def test_streaming_response_preview_template(self, client: KnockMgmt) -> None: assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_path_params_preview_template(self, client: KnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): @@ -109,9 +99,7 @@ class TestAsyncSteps: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_preview_template(self, async_client: AsyncKnockMgmt) -> None: step = await async_client.workflows.steps.preview_template( @@ -122,9 +110,7 @@ async def test_method_preview_template(self, async_client: AsyncKnockMgmt) -> No ) assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_preview_template_with_all_params(self, async_client: AsyncKnockMgmt) -> None: step = await async_client.workflows.steps.preview_template( @@ -138,9 +124,7 @@ async def test_method_preview_template_with_all_params(self, async_client: Async ) assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_preview_template(self, async_client: AsyncKnockMgmt) -> None: response = await async_client.workflows.steps.with_raw_response.preview_template( @@ -155,9 +139,7 @@ async def test_raw_response_preview_template(self, async_client: AsyncKnockMgmt) step = await response.parse() assert_matches_type(StepPreviewTemplateResponse, step, path=["response"]) - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_streaming_response_preview_template(self, async_client: AsyncKnockMgmt) -> None: async with async_client.workflows.steps.with_streaming_response.preview_template( @@ -174,9 +156,7 @@ async def test_streaming_response_preview_template(self, async_client: AsyncKnoc assert cast(Any, response.is_closed) is True - @pytest.mark.skip( - reason="currently no good way to test endpoints defining callbacks, Prism mock server will fail trying to reach the provided callback url" - ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_path_params_preview_template(self, async_client: AsyncKnockMgmt) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `workflow_key` but received ''"): From 7575d7b140452cfd8d5c88a3e5e5d4a28b9b6b9f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 14 Aug 2025 20:10:02 +0000 Subject: [PATCH 045/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/commits.py | 26 ++++++++++++++++++++++ src/knock_mapi/types/commit.py | 2 +- src/knock_mapi/types/commit_list_params.py | 13 ++++++++++- tests/api_resources/test_commits.py | 4 ++++ 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 76e0012..1debf77 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-e3ba251959cf45caea32ab451a7e848a91441902184fca8fbecc59b0e1858725.yml -openapi_spec_hash: 2ba9e807202fd4b970436522f1c1823e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-5c73cadae657fdd1d9dfe6f5f73053448e5cb428dd3117f7f5cf3d657a3a70a4.yml +openapi_spec_hash: 2399db4830e6e174ad445dc8a6dbe406 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index c10c5c5..0fb746b 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing_extensions import Literal + import httpx from ..types import commit_list_params, commit_commit_all_params, commit_promote_all_params @@ -86,6 +88,9 @@ def list( before: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, promoted: bool | NotGiven = NOT_GIVEN, + resource_id: str | NotGiven = NOT_GIVEN, + resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -110,6 +115,13 @@ def list( promoted: Whether to show commits in the given environment that have not been promoted to the subsequent environment (false) or commits which have been promoted (true). + resource_id: Filter commits by resource identifier. Must be used together with resource_type. + For most resources, this will be the resource key. In the case of translations, + this will be the locale code and namespace, separated by a `/`. For example, + `en/courses` or `en`. + + resource_type: Filter commits by resource type. Must be used together with resource_id. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -133,6 +145,8 @@ def list( "before": before, "limit": limit, "promoted": promoted, + "resource_id": resource_id, + "resource_type": resource_type, }, commit_list_params.CommitListParams, ), @@ -328,6 +342,9 @@ def list( before: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, promoted: bool | NotGiven = NOT_GIVEN, + resource_id: str | NotGiven = NOT_GIVEN, + resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -352,6 +369,13 @@ def list( promoted: Whether to show commits in the given environment that have not been promoted to the subsequent environment (false) or commits which have been promoted (true). + resource_id: Filter commits by resource identifier. Must be used together with resource_type. + For most resources, this will be the resource key. In the case of translations, + this will be the locale code and namespace, separated by a `/`. For example, + `en/courses` or `en`. + + resource_type: Filter commits by resource type. Must be used together with resource_id. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -375,6 +399,8 @@ def list( "before": before, "limit": limit, "promoted": promoted, + "resource_id": resource_id, + "resource_type": resource_type, }, commit_list_params.CommitListParams, ), diff --git a/src/knock_mapi/types/commit.py b/src/knock_mapi/types/commit.py index 30ab531..9203a4f 100644 --- a/src/knock_mapi/types/commit.py +++ b/src/knock_mapi/types/commit.py @@ -21,7 +21,7 @@ class Resource(BaseModel): identifier: str """The unique identifier for the resource.""" - type: Literal["email_layout", "workflow", "translation", "partial", "message_type"] + type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] """The type of the resource object.""" diff --git a/src/knock_mapi/types/commit_list_params.py b/src/knock_mapi/types/commit_list_params.py index 26b5b3c..ecab01d 100644 --- a/src/knock_mapi/types/commit_list_params.py +++ b/src/knock_mapi/types/commit_list_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict __all__ = ["CommitListParams"] @@ -25,3 +25,14 @@ class CommitListParams(TypedDict, total=False): Whether to show commits in the given environment that have not been promoted to the subsequent environment (false) or commits which have been promoted (true). """ + + resource_id: str + """Filter commits by resource identifier. + + Must be used together with resource_type. For most resources, this will be the + resource key. In the case of translations, this will be the locale code and + namespace, separated by a `/`. For example, `en/courses` or `en`. + """ + + resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + """Filter commits by resource type. Must be used together with resource_id.""" diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 06167e5..335f771 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -82,6 +82,8 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: before="before", limit=0, promoted=True, + resource_id="resource_id", + resource_type="email_layout", ) assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) @@ -295,6 +297,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - before="before", limit=0, promoted=True, + resource_id="resource_id", + resource_type="email_layout", ) assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) From 0c1b41076bed59f3996d9141afc9e73fca1769b2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:27:43 +0000 Subject: [PATCH 046/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/workflows/steps.py | 4 ++-- src/knock_mapi/resources/workflows/workflows.py | 4 ++-- src/knock_mapi/types/workflow_run_params.py | 2 +- .../types/workflows/step_preview_template_params.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1debf77..d5dc3b4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-5c73cadae657fdd1d9dfe6f5f73053448e5cb428dd3117f7f5cf3d657a3a70a4.yml -openapi_spec_hash: 2399db4830e6e174ad445dc8a6dbe406 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-411aa662c68a912f13a1a23b54c3f25bf725bb81ef4cf4464f7d8f3e0286032a.yml +openapi_spec_hash: fe498688ea4d1de11887463147857b36 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/workflows/steps.py b/src/knock_mapi/resources/workflows/steps.py index 39da217..a3306d9 100644 --- a/src/knock_mapi/resources/workflows/steps.py +++ b/src/knock_mapi/resources/workflows/steps.py @@ -74,7 +74,7 @@ def preview_template( data: The data to pass to the workflow template for rendering. - tenant: The tenant to associate the workflow with. + tenant: The tenant to associate the workflow with. Must not contain whitespace. extra_headers: Send extra headers @@ -163,7 +163,7 @@ async def preview_template( data: The data to pass to the workflow template for rendering. - tenant: The tenant to associate the workflow with. + tenant: The tenant to associate the workflow with. Must not contain whitespace. extra_headers: Send extra headers diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index 1faa81f..188321e 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -270,7 +270,7 @@ def run( data: A map of data to be used in the workflow run. - tenant: The tenant to associate the workflow run with. + tenant: The tenant to associate the workflow run with. Must not contain whitespace. extra_headers: Send extra headers @@ -646,7 +646,7 @@ async def run( data: A map of data to be used in the workflow run. - tenant: The tenant to associate the workflow run with. + tenant: The tenant to associate the workflow run with. Must not contain whitespace. extra_headers: Send extra headers diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index a9c4052..66c0ce3 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -34,7 +34,7 @@ class WorkflowRunParams(TypedDict, total=False): """A map of data to be used in the workflow run.""" tenant: str - """The tenant to associate the workflow run with.""" + """The tenant to associate the workflow run with. Must not contain whitespace.""" class RecipientObjectRecipientReference(TypedDict, total=False): diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index 23c9619..a688cc0 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -36,7 +36,7 @@ class StepPreviewTemplateParams(TypedDict, total=False): """The data to pass to the workflow template for rendering.""" tenant: Optional[str] - """The tenant to associate the workflow with.""" + """The tenant to associate the workflow with. Must not contain whitespace.""" class RecipientObjectRecipientReference(TypedDict, total=False): From ba727ca6dd9372015c3924ab11faa3e94214f98d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:33:08 +0000 Subject: [PATCH 047/101] chore: update github action --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 081bf0c..97951eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: run: ./scripts/lint build: - if: github.repository == 'stainless-sdks/knock-mapi-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork timeout-minutes: 10 name: build permissions: @@ -61,12 +61,14 @@ jobs: run: rye build - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/knock-mapi-python' id: github-oidc uses: actions/github-script@v6 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball + if: github.repository == 'stainless-sdks/knock-mapi-python' env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} From 914029ba51826437a11129275e5df48d049a4c57 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:28:27 +0000 Subject: [PATCH 048/101] chore(internal): change ci workflow machines --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97951eb..b5a78eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: permissions: contents: read id-token: write - runs-on: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/knock-mapi-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 From 8e12c750a414ffbb92fac0cb1509de522031a0e0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 16:06:53 +0000 Subject: [PATCH 049/101] fix: avoid newer type syntax --- src/knock_mapi/_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index b8387ce..92f7c10 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -304,7 +304,7 @@ def model_dump( exclude_none=exclude_none, ) - return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped @override def model_dump_json( From 6545a423e252a107e9aab73aee0b8ce3df7e083e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:57:03 +0000 Subject: [PATCH 050/101] chore(internal): update pyright exclude list --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index df413bb..b060689 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -148,6 +148,7 @@ exclude = [ "_dev", ".venv", ".nox", + ".git", ] reportImplicitOverride = true From 5c33cb28c71fb192aed4579e1aec0eb7e2e09a71 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:21:25 +0000 Subject: [PATCH 051/101] chore(internal): add Sequence related utils --- src/knock_mapi/_types.py | 36 ++++++++++++++++++++++++++++++- src/knock_mapi/_utils/__init__.py | 1 + src/knock_mapi/_utils/_typing.py | 5 +++++ tests/utils.py | 10 ++++++++- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/knock_mapi/_types.py b/src/knock_mapi/_types.py index f38ff3f..7669d6a 100644 --- a/src/knock_mapi/_types.py +++ b/src/knock_mapi/_types.py @@ -13,10 +13,21 @@ Mapping, TypeVar, Callable, + Iterator, Optional, Sequence, ) -from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) import httpx import pydantic @@ -217,3 +228,26 @@ class _GenericAlias(Protocol): class HttpxSendArgs(TypedDict, total=False): auth: httpx.Auth follow_redirects: bool + + +_T_co = TypeVar("_T_co", covariant=True) + + +if TYPE_CHECKING: + # This works because str.__contains__ does not accept object (either in typeshed or at runtime) + # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + class SequenceNotStr(Protocol[_T_co]): + @overload + def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... + @overload + def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... + def __contains__(self, value: object, /) -> bool: ... + def __len__(self) -> int: ... + def __iter__(self) -> Iterator[_T_co]: ... + def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... + def count(self, value: Any, /) -> int: ... + def __reversed__(self) -> Iterator[_T_co]: ... +else: + # just point this to a normal `Sequence` at runtime to avoid having to special case + # deserializing our custom sequence type + SequenceNotStr = Sequence diff --git a/src/knock_mapi/_utils/__init__.py b/src/knock_mapi/_utils/__init__.py index d4fda26..ca547ce 100644 --- a/src/knock_mapi/_utils/__init__.py +++ b/src/knock_mapi/_utils/__init__.py @@ -38,6 +38,7 @@ extract_type_arg as extract_type_arg, is_iterable_type as is_iterable_type, is_required_type as is_required_type, + is_sequence_type as is_sequence_type, is_annotated_type as is_annotated_type, is_type_alias_type as is_type_alias_type, strip_annotated_type as strip_annotated_type, diff --git a/src/knock_mapi/_utils/_typing.py b/src/knock_mapi/_utils/_typing.py index 1bac954..845cd6b 100644 --- a/src/knock_mapi/_utils/_typing.py +++ b/src/knock_mapi/_utils/_typing.py @@ -26,6 +26,11 @@ def is_list_type(typ: type) -> bool: return (get_origin(typ) or typ) == list +def is_sequence_type(typ: type) -> bool: + origin = get_origin(typ) or typ + return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence + + def is_iterable_type(typ: type) -> bool: """If the given type is `typing.Iterable[T]`""" origin = get_origin(typ) or typ diff --git a/tests/utils.py b/tests/utils.py index a6099c6..a32422d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,7 +4,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -15,6 +15,7 @@ is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, is_type_alias_type, ) @@ -71,6 +72,13 @@ def assert_matches_type( if is_list_type(type_): return _assert_list_type(type_, value) + if is_sequence_type(type_): + assert isinstance(value, Sequence) + inner_type = get_args(type_)[0] + for entry in value: # type: ignore + assert_type(inner_type, entry) # type: ignore + return + if origin == str: assert isinstance(value, str) elif origin == int: From 7399b9fc0d9c3c46e903cf1183d120397d2af9d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 30 Aug 2025 15:58:31 +0000 Subject: [PATCH 052/101] feat(api): api update --- .stats.yml | 4 ++-- api.md | 1 - src/knock_mapi/types/__init__.py | 2 -- src/knock_mapi/types/guide.py | 19 +++++++++++------- .../types/guide_activation_location_rule.py | 15 -------------- .../guide_activation_location_rule_param.py | 15 -------------- src/knock_mapi/types/guide_upsert_params.py | 20 +++++++++++-------- src/knock_mapi/types/guide_validate_params.py | 20 +++++++++++-------- tests/api_resources/test_guides.py | 8 ++++---- 9 files changed, 42 insertions(+), 62 deletions(-) delete mode 100644 src/knock_mapi/types/guide_activation_location_rule.py delete mode 100644 src/knock_mapi/types/guide_activation_location_rule_param.py diff --git a/.stats.yml b/.stats.yml index d5dc3b4..7a61e11 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-411aa662c68a912f13a1a23b54c3f25bf725bb81ef4cf4464f7d8f3e0286032a.yml -openapi_spec_hash: fe498688ea4d1de11887463147857b36 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-0dfbe42c21bfe947af931ebc42e939af23bd5b870ef3565946207f9a0df4c592.yml +openapi_spec_hash: f12e75eeb8385e431ac95ae37cf818ff config_hash: f9e83854b42d2264516f449568348afa diff --git a/api.md b/api.md index 343c550..f48b15f 100644 --- a/api.md +++ b/api.md @@ -246,7 +246,6 @@ Types: ```python from knock_mapi.types import ( Guide, - GuideActivationLocationRule, GuideStep, GuideActivateResponse, GuideUpsertResponse, diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 613e8d1..9c4818c 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -129,11 +129,9 @@ from .translation_retrieve_response import TranslationRetrieveResponse as TranslationRetrieveResponse from .translation_validate_response import TranslationValidateResponse as TranslationValidateResponse from .email_layout_validate_response import EmailLayoutValidateResponse as EmailLayoutValidateResponse -from .guide_activation_location_rule import GuideActivationLocationRule as GuideActivationLocationRule from .message_type_validate_response import MessageTypeValidateResponse as MessageTypeValidateResponse from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep as WorkflowTriggerWorkflowStep from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam as InAppFeedChannelSettingsParam -from .guide_activation_location_rule_param import GuideActivationLocationRuleParam as GuideActivationLocationRuleParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam as WorkflowTriggerWorkflowStepParam # Rebuild cyclical models only after all modules are imported. diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py index 12aaff1..5d866ad 100644 --- a/src/knock_mapi/types/guide.py +++ b/src/knock_mapi/types/guide.py @@ -2,13 +2,21 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from .._models import BaseModel from .guide_step import GuideStep from .condition_group import ConditionGroup -from .guide_activation_location_rule import GuideActivationLocationRule -__all__ = ["Guide"] +__all__ = ["Guide", "ActivationURLPattern"] + + +class ActivationURLPattern(BaseModel): + directive: Literal["allow", "block"] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: str + """The URL pathname pattern to match against. Must be a valid URI path.""" class Guide(BaseModel): @@ -37,11 +45,8 @@ class Guide(BaseModel): updated_at: datetime """The timestamp of when the guide was last updated.""" - activation_location_rules: Optional[List[GuideActivationLocationRule]] = None - """ - A list of activation location rules that describe when the guide should be - shown. - """ + activation_url_patterns: Optional[List[ActivationURLPattern]] = None + """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Optional[datetime] = None """The timestamp of when the guide was archived.""" diff --git a/src/knock_mapi/types/guide_activation_location_rule.py b/src/knock_mapi/types/guide_activation_location_rule.py deleted file mode 100644 index 78e060b..0000000 --- a/src/knock_mapi/types/guide_activation_location_rule.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from .._models import BaseModel - -__all__ = ["GuideActivationLocationRule"] - - -class GuideActivationLocationRule(BaseModel): - directive: Literal["allow", "block"] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: str - """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_activation_location_rule_param.py b/src/knock_mapi/types/guide_activation_location_rule_param.py deleted file mode 100644 index c58bd8d..0000000 --- a/src/knock_mapi/types/guide_activation_location_rule_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["GuideActivationLocationRuleParam"] - - -class GuideActivationLocationRuleParam(TypedDict, total=False): - directive: Required[Literal["allow", "block"]] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: Required[str] - """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index a793a78..b985532 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -4,14 +4,13 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam -from .guide_activation_location_rule_param import GuideActivationLocationRuleParam -__all__ = ["GuideUpsertParams", "Guide"] +__all__ = ["GuideUpsertParams", "Guide", "GuideActivationURLPattern"] class GuideUpsertParams(TypedDict, total=False): @@ -31,6 +30,14 @@ class GuideUpsertParams(TypedDict, total=False): """The message to commit the resource with, only used if `commit` is `true`.""" +class GuideActivationURLPattern(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" + + class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -41,11 +48,8 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_location_rules: Iterable[GuideActivationLocationRuleParam] - """ - A list of activation location rules that describe when the guide should be - shown. - """ + activation_url_patterns: Iterable[GuideActivationURLPattern] + """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """The timestamp of when the guide was archived.""" diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index 0bde9b9..6a2e4aa 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -4,14 +4,13 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam -from .guide_activation_location_rule_param import GuideActivationLocationRuleParam -__all__ = ["GuideValidateParams", "Guide"] +__all__ = ["GuideValidateParams", "Guide", "GuideActivationURLPattern"] class GuideValidateParams(TypedDict, total=False): @@ -22,6 +21,14 @@ class GuideValidateParams(TypedDict, total=False): """A request to create or update a guide.""" +class GuideActivationURLPattern(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" + + class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -32,11 +39,8 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_location_rules: Iterable[GuideActivationLocationRuleParam] - """ - A list of activation location rules that describe when the guide should be - shown. - """ + activation_url_patterns: Iterable[GuideActivationURLPattern] + """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] """The timestamp of when the guide was archived.""" diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index b0aaf64..09133b6 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -275,7 +275,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "values": {"text_field": "bar"}, } ], - "activation_location_rules": [ + "activation_url_patterns": [ { "directive": "allow", "pathname": "/dashboard/*", @@ -414,7 +414,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "values": {"text_field": "bar"}, } ], - "activation_location_rules": [ + "activation_url_patterns": [ { "directive": "allow", "pathname": "/dashboard/*", @@ -767,7 +767,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "values": {"text_field": "bar"}, } ], - "activation_location_rules": [ + "activation_url_patterns": [ { "directive": "allow", "pathname": "/dashboard/*", @@ -906,7 +906,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "values": {"text_field": "bar"}, } ], - "activation_location_rules": [ + "activation_url_patterns": [ { "directive": "allow", "pathname": "/dashboard/*", From b683c790f8eb0a6acd4141e455b04433023d8cec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:17:29 +0000 Subject: [PATCH 053/101] feat(types): replace List[str] with SequenceNotStr in params --- src/knock_mapi/_utils/_transform.py | 6 ++++++ src/knock_mapi/resources/workflows/workflows.py | 8 ++++---- src/knock_mapi/types/message_type_variant_param.py | 5 +++-- src/knock_mapi/types/workflow_run_params.py | 6 ++++-- src/knock_mapi/types/workflow_upsert_params.py | 5 +++-- src/knock_mapi/types/workflow_validate_params.py | 5 +++-- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/knock_mapi/_utils/_transform.py b/src/knock_mapi/_utils/_transform.py index b0cc20a..f0bcefd 100644 --- a/src/knock_mapi/_utils/_transform.py +++ b/src/knock_mapi/_utils/_transform.py @@ -16,6 +16,7 @@ lru_cache, is_mapping, is_iterable, + is_sequence, ) from .._files import is_base64_file_input from ._typing import ( @@ -24,6 +25,7 @@ extract_type_arg, is_iterable_type, is_required_type, + is_sequence_type, is_annotated_type, strip_annotated_type, ) @@ -184,6 +186,8 @@ def _transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. @@ -346,6 +350,8 @@ async def _async_transform_recursive( (is_list_type(stripped_type) and is_list(data)) # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) + # Sequence[T] + or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) ): # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually # intended as an iterable, so we don't transform it. diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index 188321e..d9a0e86 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional import httpx @@ -22,7 +22,7 @@ workflow_retrieve_params, workflow_validate_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -242,7 +242,7 @@ def run( workflow_key: str, *, environment: str, - recipients: List[workflow_run_params.Recipient], + recipients: SequenceNotStr[workflow_run_params.Recipient], actor: Optional[workflow_run_params.Actor] | NotGiven = NOT_GIVEN, cancellation_key: Optional[str] | NotGiven = NOT_GIVEN, data: Dict[str, object] | NotGiven = NOT_GIVEN, @@ -618,7 +618,7 @@ async def run( workflow_key: str, *, environment: str, - recipients: List[workflow_run_params.Recipient], + recipients: SequenceNotStr[workflow_run_params.Recipient], actor: Optional[workflow_run_params.Actor] | NotGiven = NOT_GIVEN, cancellation_key: Optional[str] | NotGiven = NOT_GIVEN, data: Dict[str, object] | NotGiven = NOT_GIVEN, diff --git a/src/knock_mapi/types/message_type_variant_param.py b/src/knock_mapi/types/message_type_variant_param.py index 1789081..4f9d0df 100644 --- a/src/knock_mapi/types/message_type_variant_param.py +++ b/src/knock_mapi/types/message_type_variant_param.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Union, Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypeAlias, TypedDict +from .._types import SequenceNotStr from .message_type_text_field_param import MessageTypeTextFieldParam __all__ = [ @@ -171,7 +172,7 @@ class FieldMessageTypeMultiSelectFieldSettingsOption(TypedDict, total=False): class FieldMessageTypeMultiSelectFieldSettings(TypedDict, total=False): - default: Optional[List[str]] + default: Optional[SequenceNotStr[str]] """The default values for the multi-select field.""" description: str diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 66c0ce3..ec3f357 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from typing_extensions import Required, TypeAlias, TypedDict +from .._types import SequenceNotStr + __all__ = [ "WorkflowRunParams", "Recipient", @@ -18,7 +20,7 @@ class WorkflowRunParams(TypedDict, total=False): environment: Required[str] """The environment slug.""" - recipients: Required[List[Recipient]] + recipients: Required[SequenceNotStr[Recipient]] """A list of recipients to run the workflow for.""" actor: Optional[Actor] diff --git a/src/knock_mapi/types/workflow_upsert_params.py b/src/knock_mapi/types/workflow_upsert_params.py index d4dc8db..e6316f6 100644 --- a/src/knock_mapi/types/workflow_upsert_params.py +++ b/src/knock_mapi/types/workflow_upsert_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr from .condition_group_param import ConditionGroupParam __all__ = ["WorkflowUpsertParams", "Workflow", "WorkflowSettings"] @@ -46,7 +47,7 @@ class Workflow(TypedDict, total=False): steps: Required[Iterable["WorkflowStepParam"]] """A list of workflow step objects in the workflow.""" - categories: List[str] + categories: SequenceNotStr[str] """ A list of [categories](https://docs.knock.app/concepts/workflows#workflow-categories) that diff --git a/src/knock_mapi/types/workflow_validate_params.py b/src/knock_mapi/types/workflow_validate_params.py index 896e83f..514b4ef 100644 --- a/src/knock_mapi/types/workflow_validate_params.py +++ b/src/knock_mapi/types/workflow_validate_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from .._types import SequenceNotStr from .condition_group_param import ConditionGroupParam __all__ = ["WorkflowValidateParams", "Workflow", "WorkflowSettings"] @@ -37,7 +38,7 @@ class Workflow(TypedDict, total=False): steps: Required[Iterable["WorkflowStepParam"]] """A list of workflow step objects in the workflow.""" - categories: List[str] + categories: SequenceNotStr[str] """ A list of [categories](https://docs.knock.app/concepts/workflows#workflow-categories) that From e278eada17a2cdbcb3115f9574a2863fa7690223 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 21:56:37 +0000 Subject: [PATCH 054/101] feat: improve future compat with pydantic v3 --- src/knock_mapi/_base_client.py | 6 +- src/knock_mapi/_compat.py | 96 +++++++------- src/knock_mapi/_models.py | 80 ++++++------ src/knock_mapi/_utils/__init__.py | 10 +- src/knock_mapi/_utils/_compat.py | 45 +++++++ src/knock_mapi/_utils/_datetime_parse.py | 136 ++++++++++++++++++++ src/knock_mapi/_utils/_transform.py | 6 +- src/knock_mapi/_utils/_typing.py | 2 +- src/knock_mapi/_utils/_utils.py | 1 - src/knock_mapi/types/__init__.py | 14 +- src/knock_mapi/types/workflow_step.py | 4 +- src/knock_mapi/types/workflow_step_param.py | 4 +- tests/test_models.py | 48 +++---- tests/test_transform.py | 16 +-- tests/test_utils/test_datetime_parse.py | 110 ++++++++++++++++ tests/utils.py | 8 +- 16 files changed, 443 insertions(+), 143 deletions(-) create mode 100644 src/knock_mapi/_utils/_compat.py create mode 100644 src/knock_mapi/_utils/_datetime_parse.py create mode 100644 tests/test_utils/test_datetime_parse.py diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index d5c6132..2b5585b 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -59,7 +59,7 @@ ModelBuilderProtocol, ) from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V2, model_copy, model_dump +from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -232,7 +232,7 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model @@ -320,7 +320,7 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model diff --git a/src/knock_mapi/_compat.py b/src/knock_mapi/_compat.py index 92d9ee6..bdef67f 100644 --- a/src/knock_mapi/_compat.py +++ b/src/knock_mapi/_compat.py @@ -12,14 +12,13 @@ _T = TypeVar("_T") _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) -# --------------- Pydantic v2 compatibility --------------- +# --------------- Pydantic v2, v3 compatibility --------------- # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V2 = pydantic.VERSION.startswith("2.") +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") -# v1 re-exports if TYPE_CHECKING: def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 @@ -44,90 +43,92 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - if PYDANTIC_V2: - from pydantic.v1.typing import ( + # v1 re-exports + if PYDANTIC_V1: + from pydantic.typing import ( get_args as get_args, is_union as is_union, get_origin as get_origin, is_typeddict as is_typeddict, is_literal_type as is_literal_type, ) - from pydantic.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: - from pydantic.typing import ( + from ._utils import ( get_args as get_args, is_union as is_union, get_origin as get_origin, + parse_date as parse_date, is_typeddict as is_typeddict, + parse_datetime as parse_datetime, is_literal_type as is_literal_type, ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime # refactored config if TYPE_CHECKING: from pydantic import ConfigDict as ConfigDict else: - if PYDANTIC_V2: - from pydantic import ConfigDict - else: + if PYDANTIC_V1: # TODO: provide an error message here? ConfigDict = None + else: + from pydantic import ConfigDict as ConfigDict # renamed methods / properties def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(value) - else: + if PYDANTIC_V1: return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + else: + return model.model_validate(value) def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V2: - return field.is_required() - return field.required # type: ignore + if PYDANTIC_V1: + return field.required # type: ignore + return field.is_required() def field_get_default(field: FieldInfo) -> Any: value = field.get_default() - if PYDANTIC_V2: - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None + if PYDANTIC_V1: return value + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None return value def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V2: - return field.annotation - return field.outer_type_ # type: ignore + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V2: - return model.model_config - return model.__config__ # type: ignore + if PYDANTIC_V1: + return model.__config__ # type: ignore + return model.model_config def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V2: - return model.model_fields - return model.__fields__ # type: ignore + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V2: - return model.model_copy(deep=deep) - return model.copy(deep=deep) # type: ignore + if PYDANTIC_V1: + return model.copy(deep=deep) # type: ignore + return model.model_copy(deep=deep) def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V2: - return model.model_dump_json(indent=indent) - return model.json(indent=indent) # type: ignore + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) def model_dump( @@ -139,14 +140,14 @@ def model_dump( warnings: bool = True, mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2 or hasattr(model, "model_dump"): + if (not PYDANTIC_V1) or hasattr(model, "model_dump"): return model.model_dump( mode=mode, exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, # warnings are not supported in Pydantic v1 - warnings=warnings if PYDANTIC_V2 else True, + warnings=True if PYDANTIC_V1 else warnings, ) return cast( "dict[str, Any]", @@ -159,9 +160,9 @@ def model_dump( def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(data) - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) # generic models @@ -170,17 +171,16 @@ def model_parse(model: type[_ModelT], data: Any) -> _ModelT: class GenericModel(pydantic.BaseModel): ... else: - if PYDANTIC_V2: + if PYDANTIC_V1: + import pydantic.generics + + class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... + else: # there no longer needs to be a distinction in v2 but # we still have to create our own subclass to avoid # inconsistent MRO ordering errors class GenericModel(pydantic.BaseModel): ... - else: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - # cached properties if TYPE_CHECKING: diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 92f7c10..3a6017e 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -50,7 +50,7 @@ strip_annotated_type, ) from ._compat import ( - PYDANTIC_V2, + PYDANTIC_V1, ConfigDict, GenericModel as BaseGenericModel, get_args, @@ -81,11 +81,7 @@ class _ConfigProtocol(Protocol): class BaseModel(pydantic.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - else: + if PYDANTIC_V1: @property @override @@ -95,6 +91,10 @@ def model_fields_set(self) -> set[str]: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] extra: Any = pydantic.Extra.allow # type: ignore + else: + model_config: ClassVar[ConfigDict] = ConfigDict( + extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) + ) def to_dict( self, @@ -215,25 +215,25 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] if key not in model_fields: parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value - if PYDANTIC_V2: - _extra[key] = parsed - else: + if PYDANTIC_V1: _fields_set.add(key) fields_values[key] = parsed + else: + _extra[key] = parsed object.__setattr__(m, "__dict__", fields_values) - if PYDANTIC_V2: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - else: + if PYDANTIC_V1: # init_private_attributes() does not exist in v2 m._init_private_attributes() # type: ignore # copied from Pydantic v1's `construct()` method object.__setattr__(m, "__fields_set__", _fields_set) + else: + # these properties are copied from Pydantic's `model_construct()` method + object.__setattr__(m, "__pydantic_private__", None) + object.__setattr__(m, "__pydantic_extra__", _extra) + object.__setattr__(m, "__pydantic_fields_set__", _fields_set) return m @@ -243,7 +243,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] # although not in practice model_construct = construct - if not PYDANTIC_V2: + if PYDANTIC_V1: # we define aliases for some of the new pydantic v2 methods so # that we can just document these methods without having to specify # a specific pydantic version as some users may not know which @@ -363,10 +363,10 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) - if PYDANTIC_V2: - type_ = field.annotation - else: + if PYDANTIC_V1: type_ = cast(type, field.outer_type_) # type: ignore + else: + type_ = field.annotation # type: ignore if type_ is None: raise RuntimeError(f"Unexpected field type is None for {key}") @@ -375,7 +375,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if not PYDANTIC_V2: + if PYDANTIC_V1: # TODO return None @@ -628,30 +628,30 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, for variant in get_args(union): variant = strip_annotated_type(variant) if is_basemodel_type(variant): - if PYDANTIC_V2: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: + if PYDANTIC_V1: + field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] + if not field_info: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] + discriminator_alias = field_info.alias - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: + if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): + for entry in get_args(annotation): if isinstance(entry, str): mapping[entry] = variant else: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: + field = _extract_field_schema_pv2(variant, discriminator_field_name) + if not field: continue # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias + discriminator_alias = field.get("serialization_alias") - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -714,7 +714,7 @@ class GenericModel(BaseGenericModel, BaseModel): pass -if PYDANTIC_V2: +if not PYDANTIC_V1: from pydantic import TypeAdapter as _TypeAdapter _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) @@ -782,12 +782,12 @@ class FinalRequestOptions(pydantic.BaseModel): json_data: Union[Body, None] = None extra_json: Union[AnyMapping, None] = None - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - else: + if PYDANTIC_V1: class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] arbitrary_types_allowed: bool = True + else: + model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) def get_max_retries(self, max_retries: int) -> int: if isinstance(self.max_retries, NotGiven): @@ -820,9 +820,9 @@ def construct( # type: ignore key: strip_not_given(value) for key, value in values.items() } - if PYDANTIC_V2: - return super().model_construct(_fields_set, **kwargs) - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + return super().model_construct(_fields_set, **kwargs) if not TYPE_CHECKING: # type checkers incorrectly complain about this assignment diff --git a/src/knock_mapi/_utils/__init__.py b/src/knock_mapi/_utils/__init__.py index ca547ce..dc64e29 100644 --- a/src/knock_mapi/_utils/__init__.py +++ b/src/knock_mapi/_utils/__init__.py @@ -10,7 +10,6 @@ lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, - parse_date as parse_date, is_iterable as is_iterable, is_sequence as is_sequence, coerce_float as coerce_float, @@ -23,7 +22,6 @@ coerce_boolean as coerce_boolean, coerce_integer as coerce_integer, file_from_path as file_from_path, - parse_datetime as parse_datetime, strip_not_given as strip_not_given, deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, @@ -32,6 +30,13 @@ maybe_coerce_boolean as maybe_coerce_boolean, maybe_coerce_integer as maybe_coerce_integer, ) +from ._compat import ( + get_args as get_args, + is_union as is_union, + get_origin as get_origin, + is_typeddict as is_typeddict, + is_literal_type as is_literal_type, +) from ._typing import ( is_list_type as is_list_type, is_union_type as is_union_type, @@ -56,3 +61,4 @@ function_has_argument as function_has_argument, assert_signatures_in_sync as assert_signatures_in_sync, ) +from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/knock_mapi/_utils/_compat.py b/src/knock_mapi/_utils/_compat.py new file mode 100644 index 0000000..dd70323 --- /dev/null +++ b/src/knock_mapi/_utils/_compat.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import sys +import typing_extensions +from typing import Any, Type, Union, Literal, Optional +from datetime import date, datetime +from typing_extensions import get_args as _get_args, get_origin as _get_origin + +from .._types import StrBytesIntFloat +from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime + +_LITERAL_TYPES = {Literal, typing_extensions.Literal} + + +def get_args(tp: type[Any]) -> tuple[Any, ...]: + return _get_args(tp) + + +def get_origin(tp: type[Any]) -> type[Any] | None: + return _get_origin(tp) + + +def is_union(tp: Optional[Type[Any]]) -> bool: + if sys.version_info < (3, 10): + return tp is Union # type: ignore[comparison-overlap] + else: + import types + + return tp is Union or tp is types.UnionType + + +def is_typeddict(tp: Type[Any]) -> bool: + return typing_extensions.is_typeddict(tp) + + +def is_literal_type(tp: Type[Any]) -> bool: + return get_origin(tp) in _LITERAL_TYPES + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + return _parse_date(value) + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + return _parse_datetime(value) diff --git a/src/knock_mapi/_utils/_datetime_parse.py b/src/knock_mapi/_utils/_datetime_parse.py new file mode 100644 index 0000000..7cb9d9e --- /dev/null +++ b/src/knock_mapi/_utils/_datetime_parse.py @@ -0,0 +1,136 @@ +""" +This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py +without the Pydantic v1 specific errors. +""" + +from __future__ import annotations + +import re +from typing import Dict, Union, Optional +from datetime import date, datetime, timezone, timedelta + +from .._types import StrBytesIntFloat + +date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" +time_expr = ( + r"(?P\d{1,2}):(?P\d{1,2})" + r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" + r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" +) + +date_re = re.compile(f"{date_expr}$") +datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") + + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) + + +def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None + + +def _from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: + if value == "Z": + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == "-": + offset = -offset + return timezone(timedelta(minutes=offset)) + else: + return None + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = _get_numeric(value, "datetime") + if number is not None: + return _from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + + match = datetime_re.match(value) + if match is None: + raise ValueError("invalid datetime format") + + kw = match.groupdict() + if kw["microsecond"]: + kw["microsecond"] = kw["microsecond"].ljust(6, "0") + + tzinfo = _parse_timezone(kw.pop("tzinfo")) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_["tzinfo"] = tzinfo + + return datetime(**kw_) # type: ignore + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = _get_numeric(value, "date") + if number is not None: + return _from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + assert not isinstance(value, (float, int)) + match = date_re.match(value) + if match is None: + raise ValueError("invalid date format") + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise ValueError("invalid date format") from None diff --git a/src/knock_mapi/_utils/_transform.py b/src/knock_mapi/_utils/_transform.py index f0bcefd..c19124f 100644 --- a/src/knock_mapi/_utils/_transform.py +++ b/src/knock_mapi/_utils/_transform.py @@ -19,6 +19,7 @@ is_sequence, ) from .._files import is_base64_file_input +from ._compat import get_origin, is_typeddict from ._typing import ( is_list_type, is_union_type, @@ -29,7 +30,6 @@ is_annotated_type, strip_annotated_type, ) -from .._compat import get_origin, model_dump, is_typeddict _T = TypeVar("_T") @@ -169,6 +169,8 @@ def _transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -333,6 +335,8 @@ async def _async_transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation diff --git a/src/knock_mapi/_utils/_typing.py b/src/knock_mapi/_utils/_typing.py index 845cd6b..193109f 100644 --- a/src/knock_mapi/_utils/_typing.py +++ b/src/knock_mapi/_utils/_typing.py @@ -15,7 +15,7 @@ from ._utils import lru_cache from .._types import InheritsGeneric -from .._compat import is_union as _is_union +from ._compat import is_union as _is_union def is_annotated_type(typ: type) -> bool: diff --git a/src/knock_mapi/_utils/_utils.py b/src/knock_mapi/_utils/_utils.py index ea3cf3f..f081859 100644 --- a/src/knock_mapi/_utils/_utils.py +++ b/src/knock_mapi/_utils/_utils.py @@ -22,7 +22,6 @@ import sniffio from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike -from .._compat import parse_date as parse_date, parse_datetime as parse_datetime _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 9c4818c..8b232f2 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -138,15 +138,15 @@ # This ensures that, when building the deferred (due to cyclical references) model schema, # Pydantic can resolve the necessary references. # See: https://github.com/pydantic/pydantic/issues/11250 for more context. -if _compat.PYDANTIC_V2: - workflow.Workflow.model_rebuild(_parent_namespace_depth=0) - workflow_branch_step.WorkflowBranchStep.model_rebuild(_parent_namespace_depth=0) - workflow_activate_response.WorkflowActivateResponse.model_rebuild(_parent_namespace_depth=0) - workflow_upsert_response.WorkflowUpsertResponse.model_rebuild(_parent_namespace_depth=0) - workflow_validate_response.WorkflowValidateResponse.model_rebuild(_parent_namespace_depth=0) -else: +if _compat.PYDANTIC_V1: workflow.Workflow.update_forward_refs() # type: ignore workflow_branch_step.WorkflowBranchStep.update_forward_refs() # type: ignore workflow_activate_response.WorkflowActivateResponse.update_forward_refs() # type: ignore workflow_upsert_response.WorkflowUpsertResponse.update_forward_refs() # type: ignore workflow_validate_response.WorkflowValidateResponse.update_forward_refs() # type: ignore +else: + workflow.Workflow.model_rebuild(_parent_namespace_depth=0) + workflow_branch_step.WorkflowBranchStep.model_rebuild(_parent_namespace_depth=0) + workflow_activate_response.WorkflowActivateResponse.model_rebuild(_parent_namespace_depth=0) + workflow_upsert_response.WorkflowUpsertResponse.model_rebuild(_parent_namespace_depth=0) + workflow_validate_response.WorkflowValidateResponse.model_rebuild(_parent_namespace_depth=0) diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py index f6ee72a..e5b8a66 100644 --- a/src/knock_mapi/types/workflow_step.py +++ b/src/knock_mapi/types/workflow_step.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Union from typing_extensions import TypeAlias, TypeAliasType -from .._compat import PYDANTIC_V2 +from .._compat import PYDANTIC_V1 from .workflow_batch_step import WorkflowBatchStep from .workflow_delay_step import WorkflowDelayStep from .workflow_fetch_step import WorkflowFetchStep @@ -15,7 +15,7 @@ __all__ = ["WorkflowStep"] -if TYPE_CHECKING or PYDANTIC_V2: +if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStep = TypeAliasType( "WorkflowStep", Union[ diff --git a/src/knock_mapi/types/workflow_step_param.py b/src/knock_mapi/types/workflow_step_param.py index 52d5618..88a518f 100644 --- a/src/knock_mapi/types/workflow_step_param.py +++ b/src/knock_mapi/types/workflow_step_param.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Union from typing_extensions import TypeAlias, TypeAliasType -from .._compat import PYDANTIC_V2 +from .._compat import PYDANTIC_V1 from .workflow_batch_step_param import WorkflowBatchStepParam from .workflow_delay_step_param import WorkflowDelayStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam @@ -15,7 +15,7 @@ __all__ = ["WorkflowStepParam"] -if TYPE_CHECKING or PYDANTIC_V2: +if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStepParam = TypeAliasType( "WorkflowStepParam", Union[ diff --git a/tests/test_models.py b/tests/test_models.py index 6fb121f..522ff87 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -8,7 +8,7 @@ from pydantic import Field from knock_mapi._utils import PropertyInfo -from knock_mapi._compat import PYDANTIC_V2, parse_obj, model_dump, model_json +from knock_mapi._compat import PYDANTIC_V1, parse_obj, model_dump, model_json from knock_mapi._models import BaseModel, construct_type @@ -294,12 +294,12 @@ class Model(BaseModel): assert cast(bool, m.foo) is True m = Model.construct(foo={"name": 3}) - if PYDANTIC_V2: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - else: + if PYDANTIC_V1: assert isinstance(m.foo, Submodel2) assert m.foo.name == "3" + else: + assert isinstance(m.foo, Submodel1) + assert m.foo.name == 3 # type: ignore def test_list_of_unions() -> None: @@ -426,10 +426,10 @@ class Model(BaseModel): expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - if PYDANTIC_V2: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - else: + if PYDANTIC_V1: expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' + else: + expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' model = Model.construct(created_at="2019-12-27T18:11:19.117Z") assert model.created_at == expected @@ -531,7 +531,7 @@ class Model2(BaseModel): assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} assert m4.to_dict(mode="json") == {"created_at": time_str} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -556,7 +556,7 @@ class Model(BaseModel): assert m3.model_dump() == {"foo": None} assert m3.model_dump(exclude_none=True) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -580,10 +580,10 @@ class Model(BaseModel): assert json.loads(m.to_json()) == {"FOO": "hello"} assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} - if PYDANTIC_V2: - assert m.to_json(indent=None) == '{"FOO":"hello"}' - else: + if PYDANTIC_V1: assert m.to_json(indent=None) == '{"FOO": "hello"}' + else: + assert m.to_json(indent=None) == '{"FOO":"hello"}' m2 = Model() assert json.loads(m2.to_json()) == {} @@ -595,7 +595,7 @@ class Model(BaseModel): assert json.loads(m3.to_json()) == {"FOO": None} assert json.loads(m3.to_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_json(warnings=False) @@ -622,7 +622,7 @@ class Model(BaseModel): assert json.loads(m3.model_dump_json()) == {"foo": None} assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump_json(round_trip=True) @@ -679,12 +679,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_unknown_variant() -> None: @@ -768,12 +768,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.foo_type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + if PYDANTIC_V1: # pydantic v1 automatically converts inputs to strings # if the expected type is a str assert m.data == "100" + else: + assert m.data == 100 # type: ignore[comparison-overlap] def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: @@ -833,7 +833,7 @@ class B(BaseModel): assert UnionType.__discriminator__ is discriminator -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_type_alias_type() -> None: Alias = TypeAliasType("Alias", str) # pyright: ignore @@ -849,7 +849,7 @@ class Model(BaseModel): assert m.union == "bar" -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_field_named_cls() -> None: class Model(BaseModel): cls: str @@ -936,7 +936,7 @@ class Type2(BaseModel): assert isinstance(model.value, InnerType2) -@pytest.mark.skipif(not PYDANTIC_V2, reason="this is only supported in pydantic v2 for now") +@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") def test_extra_properties() -> None: class Item(BaseModel): prop: int diff --git a/tests/test_transform.py b/tests/test_transform.py index 6db6a29..c3a7563 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -15,7 +15,7 @@ parse_datetime, async_transform as _async_transform, ) -from knock_mapi._compat import PYDANTIC_V2 +from knock_mapi._compat import PYDANTIC_V1 from knock_mapi._models import BaseModel _T = TypeVar("_T") @@ -189,7 +189,7 @@ class DateModel(BaseModel): @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - tz = "Z" if PYDANTIC_V2 else "+00:00" + tz = "+00:00" if PYDANTIC_V1 else "Z" assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] @@ -297,11 +297,11 @@ async def test_pydantic_unknown_field(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_types(use_async: bool) -> None: model = MyModel.construct(foo=True) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": True} @@ -309,11 +309,11 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_object_type(use_async: bool) -> None: model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": {"hello": "world"}} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py new file mode 100644 index 0000000..57abb5b --- /dev/null +++ b/tests/test_utils/test_datetime_parse.py @@ -0,0 +1,110 @@ +""" +Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py +with modifications so it works without pydantic v1 imports. +""" + +from typing import Type, Union +from datetime import date, datetime, timezone, timedelta + +import pytest + +from knock_mapi._utils import parse_date, parse_datetime + + +def create_tz(minutes: int) -> timezone: + return timezone(timedelta(minutes=minutes)) + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + ("1494012444.883309", date(2017, 5, 5)), + (b"1494012444.883309", date(2017, 5, 5)), + (1_494_012_444.883_309, date(2017, 5, 5)), + ("1494012444", date(2017, 5, 5)), + (1_494_012_444, date(2017, 5, 5)), + (0, date(1970, 1, 1)), + ("2012-04-23", date(2012, 4, 23)), + (b"2012-04-23", date(2012, 4, 23)), + ("2012-4-9", date(2012, 4, 9)), + (date(2012, 4, 9), date(2012, 4, 9)), + (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), + # Invalid inputs + ("x20120423", ValueError), + ("2012-04-56", ValueError), + (19_999_999_999, date(2603, 10, 11)), # just before watershed + (20_000_000_001, date(1970, 8, 20)), # just after watershed + (1_549_316_052, date(2019, 2, 4)), # nowish in s + (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms + (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs + (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns + ("infinity", date(9999, 12, 31)), + ("inf", date(9999, 12, 31)), + (float("inf"), date(9999, 12, 31)), + ("infinity ", date(9999, 12, 31)), + (int("1" + "0" * 100), date(9999, 12, 31)), + (1e1000, date(9999, 12, 31)), + ("-infinity", date(1, 1, 1)), + ("-inf", date(1, 1, 1)), + ("nan", ValueError), + ], +) +def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_date(value) + else: + assert parse_date(value) == result + + +@pytest.mark.parametrize( + "value,result", + [ + # Valid inputs + # values in seconds + ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), + ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + # values in ms + ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), + ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), + (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), + ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), + ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), + ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), + ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), + ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), + ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), + ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), + (datetime(2017, 5, 5), datetime(2017, 5, 5)), + (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), + # Invalid inputs + ("x20120423091500", ValueError), + ("2012-04-56T09:15:90", ValueError), + ("2012-04-23T11:05:00-25:00", ValueError), + (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed + (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed + (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s + (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms + (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs + (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns + ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), + (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), + (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), + ("-infinity", datetime(1, 1, 1, 0, 0)), + ("-inf", datetime(1, 1, 1, 0, 0)), + ("nan", ValueError), + ], +) +def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: + if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] + with pytest.raises(result): + parse_datetime(value) + else: + assert parse_datetime(value) == result diff --git a/tests/utils.py b/tests/utils.py index a32422d..6ec99c8 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -19,7 +19,7 @@ is_annotated_type, is_type_alias_type, ) -from knock_mapi._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from knock_mapi._compat import PYDANTIC_V1, field_outer_type, get_model_fields from knock_mapi._models import BaseModel BaseModelT = TypeVar("BaseModelT", bound=BaseModel) @@ -28,12 +28,12 @@ def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: for name, field in get_model_fields(model).items(): field_value = getattr(value, name) - if PYDANTIC_V2: - allow_none = False - else: + if PYDANTIC_V1: # in v1 nullability was structured differently # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields allow_none = getattr(field, "allow_none", False) + else: + allow_none = False assert_matches_type( field_outer_type(field), From e1c9f432350da84660420a1bfc2ac49a813ccd11 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:50:29 +0000 Subject: [PATCH 055/101] chore(internal): move mypy configurations to `pyproject.toml` file --- mypy.ini | 50 ------------------------------------------------ pyproject.toml | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 50 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index be72489..0000000 --- a/mypy.ini +++ /dev/null @@ -1,50 +0,0 @@ -[mypy] -pretty = True -show_error_codes = True - -# Exclude _files.py because mypy isn't smart enough to apply -# the correct type narrowing and as this is an internal module -# it's fine to just use Pyright. -# -# We also exclude our `tests` as mypy doesn't always infer -# types correctly and Pyright will still catch any type errors. -exclude = ^(src/knock_mapi/_files\.py|_dev/.*\.py|tests/.*)$ - -strict_equality = True -implicit_reexport = True -check_untyped_defs = True -no_implicit_optional = True - -warn_return_any = True -warn_unreachable = True -warn_unused_configs = True - -# Turn these options off as it could cause conflicts -# with the Pyright options. -warn_unused_ignores = False -warn_redundant_casts = False - -disallow_any_generics = True -disallow_untyped_defs = True -disallow_untyped_calls = True -disallow_subclassing_any = True -disallow_incomplete_defs = True -disallow_untyped_decorators = True -cache_fine_grained = True - -# By default, mypy reports an error if you assign a value to the result -# of a function call that doesn't return anything. We do this in our test -# cases: -# ``` -# result = ... -# assert result is None -# ``` -# Changing this codegen to make mypy happy would increase complexity -# and would not be worth it. -disable_error_code = func-returns-value,overload-cannot-match - -# https://github.com/python/mypy/issues/12162 -[mypy.overrides] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index b060689..da2f194 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,6 +157,58 @@ reportOverlappingOverload = false reportImportCycles = false reportPrivateUsage = false +[tool.mypy] +pretty = true +show_error_codes = true + +# Exclude _files.py because mypy isn't smart enough to apply +# the correct type narrowing and as this is an internal module +# it's fine to just use Pyright. +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ['src/knock_mapi/_files.py', '_dev/.*.py', 'tests/.*'] + +strict_equality = true +implicit_reexport = true +check_untyped_defs = true +no_implicit_optional = true + +warn_return_any = true +warn_unreachable = true +warn_unused_configs = true + +# Turn these options off as it could cause conflicts +# with the Pyright options. +warn_unused_ignores = false +warn_redundant_casts = false + +disallow_any_generics = true +disallow_untyped_defs = true +disallow_untyped_calls = true +disallow_subclassing_any = true +disallow_incomplete_defs = true +disallow_untyped_decorators = true +cache_fine_grained = true + +# By default, mypy reports an error if you assign a value to the result +# of a function call that doesn't return anything. We do this in our test +# cases: +# ``` +# result = ... +# assert result is None +# ``` +# Changing this codegen to make mypy happy would increase complexity +# and would not be worth it. +disable_error_code = "func-returns-value,overload-cannot-match" + +# https://github.com/python/mypy/issues/12162 +[[tool.mypy.overrides]] +module = "black.files.*" +ignore_errors = true +ignore_missing_imports = true + + [tool.ruff] line-length = 120 output-format = "grouped" From dacad65d1ef5042803226b3f2f584a7ce16aa197 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 21:27:31 +0000 Subject: [PATCH 056/101] chore(tests): simplify `get_platform` test `nest_asyncio` is archived and broken on some platforms so it's not worth keeping in our test suite. --- pyproject.toml | 1 - requirements-dev.lock | 1 - tests/test_client.py | 53 +++++-------------------------------------- 3 files changed, 6 insertions(+), 49 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index da2f194..581c63e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,7 +56,6 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", - "nest_asyncio==1.6.0", "pytest-xdist>=3.6.1", ] diff --git a/requirements-dev.lock b/requirements-dev.lock index 96238fe..95d1628 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -75,7 +75,6 @@ multidict==6.4.4 mypy==1.14.1 mypy-extensions==1.0.0 # via mypy -nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 diff --git a/tests/test_client.py b/tests/test_client.py index 1245096..96a8cf8 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,13 +6,10 @@ import os import sys import json -import time import asyncio import inspect -import subprocess import tracemalloc from typing import Any, Union, cast -from textwrap import dedent from unittest import mock from typing_extensions import Literal @@ -23,14 +20,17 @@ from knock_mapi import KnockMgmt, AsyncKnockMgmt, APIResponseValidationError from knock_mapi._types import Omit +from knock_mapi._utils import asyncify from knock_mapi._models import BaseModel, FinalRequestOptions from knock_mapi._exceptions import APIStatusError, KnockMgmtError, APIResponseValidationError from knock_mapi._base_client import ( DEFAULT_TIMEOUT, HTTPX_DEFAULT_TIMEOUT, BaseClient, + OtherPlatform, DefaultHttpxClient, DefaultAsyncHttpxClient, + get_platform, make_request_options, ) @@ -1657,50 +1657,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" - def test_get_platform(self) -> None: - # A previous implementation of asyncify could leave threads unterminated when - # used with nest_asyncio. - # - # Since nest_asyncio.apply() is global and cannot be un-applied, this - # test is run in a separate process to avoid affecting other tests. - test_code = dedent(""" - import asyncio - import nest_asyncio - import threading - - from knock_mapi._utils import asyncify - from knock_mapi._base_client import get_platform - - async def test_main() -> None: - result = await asyncify(get_platform)() - print(result) - for thread in threading.enumerate(): - print(thread.name) - - nest_asyncio.apply() - asyncio.run(test_main()) - """) - with subprocess.Popen( - [sys.executable, "-c", test_code], - text=True, - ) as process: - timeout = 10 # seconds - - start_time = time.monotonic() - while True: - return_code = process.poll() - if return_code is not None: - if return_code != 0: - raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") - - # success - break - - if time.monotonic() - start_time > timeout: - process.kill() - raise AssertionError("calling get_platform using asyncify resulted in a hung process") - - time.sleep(0.1) + async def test_get_platform(self) -> None: + platform = await asyncify(get_platform)() + assert isinstance(platform, (str, OtherPlatform)) async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly From 7008cf73bfd891d6f4021077c5d63d00b93e7669 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:57:27 +0000 Subject: [PATCH 057/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/auth.py | 12 ++++++++++-- src/knock_mapi/types/auth_verify_response.py | 9 ++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7a61e11..89a1d1b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-0dfbe42c21bfe947af931ebc42e939af23bd5b870ef3565946207f9a0df4c592.yml -openapi_spec_hash: f12e75eeb8385e431ac95ae37cf818ff +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b1bfc3fcd728100cedbf5e3ad84d95135be689718a2662146afdef0240ddbe5a.yml +openapi_spec_hash: 62febab5af534d5627c2e0dd4c6aeec7 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/auth.py b/src/knock_mapi/resources/auth.py index 3da0bbb..2cda590 100644 --- a/src/knock_mapi/resources/auth.py +++ b/src/knock_mapi/resources/auth.py @@ -49,7 +49,11 @@ def verify( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AuthVerifyResponse: - """Return information about the current service token.""" + """Return information about the current calling scope. + + Will either be a service + token or from an OAuth context. + """ return self._get( "/v1/whoami", options=make_request_options( @@ -89,7 +93,11 @@ async def verify( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AuthVerifyResponse: - """Return information about the current service token.""" + """Return information about the current calling scope. + + Will either be a service + token or from an OAuth context. + """ return await self._get( "/v1/whoami", options=make_request_options( diff --git a/src/knock_mapi/types/auth_verify_response.py b/src/knock_mapi/types/auth_verify_response.py index 4f2620c..ce528ed 100644 --- a/src/knock_mapi/types/auth_verify_response.py +++ b/src/knock_mapi/types/auth_verify_response.py @@ -1,5 +1,8 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing import Optional +from typing_extensions import Literal + from .._models import BaseModel __all__ = ["AuthVerifyResponse"] @@ -10,4 +13,8 @@ class AuthVerifyResponse(BaseModel): account_slug: str - service_token_name: str + type: Literal["service_token", "oauth_context"] + + service_token_name: Optional[str] = None + + user_id: Optional[str] = None From 36dcd956b0f8f4881546271d21bccd8b774863aa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:30:29 +0000 Subject: [PATCH 058/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/channels.py | 8 ++++++++ src/knock_mapi/types/channel.py | 3 +++ src/knock_mapi/types/channel_list_params.py | 3 +++ tests/api_resources/test_channels.py | 2 ++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 89a1d1b..8ef95c3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b1bfc3fcd728100cedbf5e3ad84d95135be689718a2662146afdef0240ddbe5a.yml -openapi_spec_hash: 62febab5af534d5627c2e0dd4c6aeec7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b90dac2a045de60a7d3f873aa4e800f236a9800b15b553fd0b62318193dab8fb.yml +openapi_spec_hash: 61d2dd8fc14bd2c53af4d764d42cf9bd config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/channels.py b/src/knock_mapi/resources/channels.py index 3f650b1..f868469 100644 --- a/src/knock_mapi/resources/channels.py +++ b/src/knock_mapi/resources/channels.py @@ -45,6 +45,7 @@ def with_streaming_response(self) -> ChannelsResourceWithStreamingResponse: def list( self, *, + id: str | NotGiven = NOT_GIVEN, after: str | NotGiven = NOT_GIVEN, before: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, @@ -61,6 +62,8 @@ def list( entire account, not scoped to an environment. Args: + id: A channel id to filter the results by. + after: The cursor to fetch entries after. before: The cursor to fetch entries before. @@ -85,6 +88,7 @@ def list( timeout=timeout, query=maybe_transform( { + "id": id, "after": after, "before": before, "limit": limit, @@ -119,6 +123,7 @@ def with_streaming_response(self) -> AsyncChannelsResourceWithStreamingResponse: def list( self, *, + id: str | NotGiven = NOT_GIVEN, after: str | NotGiven = NOT_GIVEN, before: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, @@ -135,6 +140,8 @@ def list( entire account, not scoped to an environment. Args: + id: A channel id to filter the results by. + after: The cursor to fetch entries after. before: The cursor to fetch entries before. @@ -159,6 +166,7 @@ def list( timeout=timeout, query=maybe_transform( { + "id": id, "after": after, "before": before, "limit": limit, diff --git a/src/knock_mapi/types/channel.py b/src/knock_mapi/types/channel.py index 87fd918..a9a98d6 100644 --- a/src/knock_mapi/types/channel.py +++ b/src/knock_mapi/types/channel.py @@ -10,6 +10,9 @@ class Channel(BaseModel): + id: str + """The unique identifier for the channel.""" + created_at: datetime """The timestamp of when the channel was created.""" diff --git a/src/knock_mapi/types/channel_list_params.py b/src/knock_mapi/types/channel_list_params.py index 3136ca7..b1a5df7 100644 --- a/src/knock_mapi/types/channel_list_params.py +++ b/src/knock_mapi/types/channel_list_params.py @@ -8,6 +8,9 @@ class ChannelListParams(TypedDict, total=False): + id: str + """A channel id to filter the results by.""" + after: str """The cursor to fetch entries after.""" diff --git a/tests/api_resources/test_channels.py b/tests/api_resources/test_channels.py index 2bbbc80..3b7f9d1 100644 --- a/tests/api_resources/test_channels.py +++ b/tests/api_resources/test_channels.py @@ -28,6 +28,7 @@ def test_method_list(self, client: KnockMgmt) -> None: @parametrize def test_method_list_with_all_params(self, client: KnockMgmt) -> None: channel = client.channels.list( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", after="after", before="before", limit=0, @@ -72,6 +73,7 @@ async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: channel = await async_client.channels.list( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", after="after", before="before", limit=0, From 7defb9ea2c11bbe100c1427f1f89e50038cbec30 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 19:14:33 +0000 Subject: [PATCH 059/101] chore(internal): update pydantic dependency --- requirements-dev.lock | 7 +++++-- requirements.lock | 7 +++++-- src/knock_mapi/_models.py | 14 ++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/requirements-dev.lock b/requirements-dev.lock index 95d1628..050552d 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -88,9 +88,9 @@ pluggy==1.5.0 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.10.3 +pydantic==2.11.9 # via knock-mapi -pydantic-core==2.27.1 +pydantic-core==2.33.2 # via pydantic pygments==2.18.0 # via rich @@ -126,6 +126,9 @@ typing-extensions==4.12.2 # via pydantic # via pydantic-core # via pyright + # via typing-inspection +typing-inspection==0.4.1 + # via pydantic virtualenv==20.24.5 # via nox yarl==1.20.0 diff --git a/requirements.lock b/requirements.lock index 2461e81..b43763a 100644 --- a/requirements.lock +++ b/requirements.lock @@ -55,9 +55,9 @@ multidict==6.4.4 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.10.3 +pydantic==2.11.9 # via knock-mapi -pydantic-core==2.27.1 +pydantic-core==2.33.2 # via pydantic sniffio==1.3.0 # via anyio @@ -68,5 +68,8 @@ typing-extensions==4.12.2 # via multidict # via pydantic # via pydantic-core + # via typing-inspection +typing-inspection==0.4.1 + # via pydantic yarl==1.20.0 # via aiohttp diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 3a6017e..6a3cd1d 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -256,7 +256,7 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, @@ -264,6 +264,7 @@ def model_dump( warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, serialize_as_any: bool = False, + fallback: Callable[[Any], Any] | None = None, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -295,10 +296,12 @@ def model_dump( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, @@ -313,13 +316,14 @@ def model_dump_json( indent: int | None = None, include: IncEx | None = None, exclude: IncEx | None = None, - by_alias: bool = False, + by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, context: dict[str, Any] | None = None, + fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json @@ -348,11 +352,13 @@ def model_dump_json( raise ValueError("context is only supported in Pydantic v2") if serialize_as_any != False: raise ValueError("serialize_as_any is only supported in Pydantic v2") + if fallback is not None: + raise ValueError("fallback is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias if by_alias is not None else False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, From 02af8f0a2b0904f9c1b031a14d0b2424f1c286f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 15:00:43 +0000 Subject: [PATCH 060/101] chore(types): change optional parameter type from NotGiven to Omit --- src/knock_mapi/__init__.py | 4 +- src/knock_mapi/_base_client.py | 18 ++-- src/knock_mapi/_client.py | 16 ++-- src/knock_mapi/_qs.py | 14 +-- src/knock_mapi/_types.py | 29 +++--- src/knock_mapi/_utils/_transform.py | 4 +- src/knock_mapi/_utils/_utils.py | 8 +- src/knock_mapi/resources/api_keys.py | 6 +- src/knock_mapi/resources/auth.py | 6 +- src/knock_mapi/resources/channel_groups.py | 18 ++-- src/knock_mapi/resources/channels.py | 22 ++--- src/knock_mapi/resources/commits.py | 50 +++++------ src/knock_mapi/resources/email_layouts.py | 58 ++++++------ src/knock_mapi/resources/environments.py | 22 ++--- src/knock_mapi/resources/guides.py | 90 +++++++++---------- src/knock_mapi/resources/message_types.py | 58 ++++++------ src/knock_mapi/resources/partials.py | 58 ++++++------ src/knock_mapi/resources/translations.py | 82 ++++++++--------- src/knock_mapi/resources/variables.py | 18 ++-- src/knock_mapi/resources/workflows/steps.py | 18 ++-- .../resources/workflows/workflows.py | 82 ++++++++--------- tests/test_transform.py | 11 ++- 22 files changed, 354 insertions(+), 338 deletions(-) diff --git a/src/knock_mapi/__init__.py b/src/knock_mapi/__init__.py index bc4d532..e41a2d2 100644 --- a/src/knock_mapi/__init__.py +++ b/src/knock_mapi/__init__.py @@ -3,7 +3,7 @@ import typing as _t from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given from ._utils import file_from_path from ._client import ( Client, @@ -48,7 +48,9 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "not_given", "Omit", + "omit", "KnockMgmtError", "APIError", "APIStatusError", diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index 2b5585b..3b0b3e4 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -42,7 +42,6 @@ from ._qs import Querystring from ._files import to_httpx_files, async_to_httpx_files from ._types import ( - NOT_GIVEN, Body, Omit, Query, @@ -57,6 +56,7 @@ RequestOptions, HttpxRequestFiles, ModelBuilderProtocol, + not_given, ) from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping from ._compat import PYDANTIC_V1, model_copy, model_dump @@ -145,9 +145,9 @@ def __init__( def __init__( self, *, - url: URL | NotGiven = NOT_GIVEN, - json: Body | NotGiven = NOT_GIVEN, - params: Query | NotGiven = NOT_GIVEN, + url: URL | NotGiven = not_given, + json: Body | NotGiven = not_given, + params: Query | NotGiven = not_given, ) -> None: self.url = url self.json = json @@ -595,7 +595,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques # we internally support defining a temporary header to override the # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN) + override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) if is_given(override_cast_to): options.headers = headers return cast(Type[ResponseT], override_cast_to) @@ -825,7 +825,7 @@ def __init__( version: str, base_url: str | URL, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1356,7 +1356,7 @@ def __init__( base_url: str | URL, _strict_response_validation: bool, max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, @@ -1818,8 +1818,8 @@ def make_request_options( extra_query: Query | None = None, extra_body: Body | None = None, idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - post_parser: PostParser | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + post_parser: PostParser | NotGiven = not_given, ) -> RequestOptions: """Create a dict of type RequestOptions without keys of NotGiven values.""" options: RequestOptions = {} diff --git a/src/knock_mapi/_client.py b/src/knock_mapi/_client.py index 937aeab..716d891 100644 --- a/src/knock_mapi/_client.py +++ b/src/knock_mapi/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import Any, Mapping from typing_extensions import Self, override import httpx @@ -11,13 +11,13 @@ from . import _exceptions from ._qs import Querystring from ._types import ( - NOT_GIVEN, Omit, Timeout, NotGiven, Transport, ProxiesTypes, RequestOptions, + not_given, ) from ._utils import is_given, get_async_library from ._version import __version__ @@ -81,7 +81,7 @@ def __init__( *, service_token: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -168,9 +168,9 @@ def copy( *, service_token: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.Client | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -273,7 +273,7 @@ def __init__( *, service_token: str | None = None, base_url: str | httpx.URL | None = None, - timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, @@ -360,9 +360,9 @@ def copy( *, service_token: str | None = None, base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | Timeout | None | NotGiven = not_given, http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = NOT_GIVEN, + max_retries: int | NotGiven = not_given, default_headers: Mapping[str, str] | None = None, set_default_headers: Mapping[str, str] | None = None, default_query: Mapping[str, object] | None = None, diff --git a/src/knock_mapi/_qs.py b/src/knock_mapi/_qs.py index 274320c..ada6fd3 100644 --- a/src/knock_mapi/_qs.py +++ b/src/knock_mapi/_qs.py @@ -4,7 +4,7 @@ from urllib.parse import parse_qs, urlencode from typing_extensions import Literal, get_args -from ._types import NOT_GIVEN, NotGiven, NotGivenOr +from ._types import NotGiven, not_given from ._utils import flatten _T = TypeVar("_T") @@ -41,8 +41,8 @@ def stringify( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> str: return urlencode( self.stringify_items( @@ -56,8 +56,8 @@ def stringify_items( self, params: Params, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> list[tuple[str, str]]: opts = Options( qs=self, @@ -143,8 +143,8 @@ def __init__( self, qs: Querystring = _qs, *, - array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN, - nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN, + array_format: ArrayFormat | NotGiven = not_given, + nested_format: NestedFormat | NotGiven = not_given, ) -> None: self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/knock_mapi/_types.py b/src/knock_mapi/_types.py index 7669d6a..d12145b 100644 --- a/src/knock_mapi/_types.py +++ b/src/knock_mapi/_types.py @@ -117,18 +117,21 @@ class RequestOptions(TypedDict, total=False): # Sentinel class used until PEP 0661 is accepted class NotGiven: """ - A sentinel singleton class used to distinguish omitted keyword arguments - from those passed in with the value None (which may have different behavior). + For parameters with a meaningful None value, we need to distinguish between + the user explicitly passing None, and the user not passing the parameter at + all. + + User code shouldn't need to use not_given directly. For example: ```py - def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ... + def create(timeout: Timeout | None | NotGiven = not_given): ... - get(timeout=1) # 1s timeout - get(timeout=None) # No timeout - get() # Default timeout behavior, which may not be statically known at the method definition. + create(timeout=1) # 1s timeout + create(timeout=None) # No timeout + create() # Default timeout behavior ``` """ @@ -140,13 +143,14 @@ def __repr__(self) -> str: return "NOT_GIVEN" -NotGivenOr = Union[_T, NotGiven] +not_given = NotGiven() +# for backwards compatibility: NOT_GIVEN = NotGiven() class Omit: - """In certain situations you need to be able to represent a case where a default value has - to be explicitly removed and `None` is not an appropriate substitute, for example: + """ + To explicitly omit something from being sent in a request, use `omit`. ```py # as the default `Content-Type` header is `application/json` that will be sent @@ -156,8 +160,8 @@ class Omit: # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' client.post(..., headers={"Content-Type": "multipart/form-data"}) - # instead you can remove the default `application/json` header by passing Omit - client.post(..., headers={"Content-Type": Omit()}) + # instead you can remove the default `application/json` header by passing omit + client.post(..., headers={"Content-Type": omit}) ``` """ @@ -165,6 +169,9 @@ def __bool__(self) -> Literal[False]: return False +omit = Omit() + + @runtime_checkable class ModelBuilderProtocol(Protocol): @classmethod diff --git a/src/knock_mapi/_utils/_transform.py b/src/knock_mapi/_utils/_transform.py index c19124f..5207549 100644 --- a/src/knock_mapi/_utils/_transform.py +++ b/src/knock_mapi/_utils/_transform.py @@ -268,7 +268,7 @@ def _transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue @@ -434,7 +434,7 @@ async def _async_transform_typeddict( annotations = get_type_hints(expected_type, include_extras=True) for key, value in data.items(): if not is_given(value): - # we don't need to include `NotGiven` values here as they'll + # we don't need to include omitted values here as they'll # be stripped out before the request is sent anyway continue diff --git a/src/knock_mapi/_utils/_utils.py b/src/knock_mapi/_utils/_utils.py index f081859..50d5926 100644 --- a/src/knock_mapi/_utils/_utils.py +++ b/src/knock_mapi/_utils/_utils.py @@ -21,7 +21,7 @@ import sniffio -from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike +from .._types import Omit, NotGiven, FileTypes, HeadersLike _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) @@ -63,7 +63,7 @@ def _extract_items( try: key = path[index] except IndexError: - if isinstance(obj, NotGiven): + if not is_given(obj): # no value was provided - we can safely ignore return [] @@ -126,8 +126,8 @@ def _extract_items( return [] -def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) +def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: + return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) # Type safe methods for narrowing types with TypeVars. diff --git a/src/knock_mapi/resources/api_keys.py b/src/knock_mapi/resources/api_keys.py index 4ead617..93a2874 100644 --- a/src/knock_mapi/resources/api_keys.py +++ b/src/knock_mapi/resources/api_keys.py @@ -5,7 +5,7 @@ import httpx from ..types import api_key_exchange_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -50,7 +50,7 @@ def exchange( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyExchangeResponse: """ Given an authenticated service token and an environment, will exchange the @@ -110,7 +110,7 @@ async def exchange( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> APIKeyExchangeResponse: """ Given an authenticated service token and an environment, will exchange the diff --git a/src/knock_mapi/resources/auth.py b/src/knock_mapi/resources/auth.py index 2cda590..683ad74 100644 --- a/src/knock_mapi/resources/auth.py +++ b/src/knock_mapi/resources/auth.py @@ -4,7 +4,7 @@ import httpx -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Query, Headers, NotGiven, not_given from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource from .._response import ( @@ -47,7 +47,7 @@ def verify( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthVerifyResponse: """Return information about the current calling scope. @@ -91,7 +91,7 @@ async def verify( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AuthVerifyResponse: """Return information about the current calling scope. diff --git a/src/knock_mapi/resources/channel_groups.py b/src/knock_mapi/resources/channel_groups.py index 8797bb8..8227aca 100644 --- a/src/knock_mapi/resources/channel_groups.py +++ b/src/knock_mapi/resources/channel_groups.py @@ -5,7 +5,7 @@ import httpx from ..types import channel_group_list_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -45,15 +45,15 @@ def with_streaming_response(self) -> ChannelGroupsResourceWithStreamingResponse: def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[ChannelGroup]: """Returns a paginated list of channel groups. @@ -119,15 +119,15 @@ def with_streaming_response(self) -> AsyncChannelGroupsResourceWithStreamingResp def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[ChannelGroup, AsyncEntriesCursor[ChannelGroup]]: """Returns a paginated list of channel groups. diff --git a/src/knock_mapi/resources/channels.py b/src/knock_mapi/resources/channels.py index f868469..de75a2e 100644 --- a/src/knock_mapi/resources/channels.py +++ b/src/knock_mapi/resources/channels.py @@ -5,7 +5,7 @@ import httpx from ..types import channel_list_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -45,16 +45,16 @@ def with_streaming_response(self) -> ChannelsResourceWithStreamingResponse: def list( self, *, - id: str | NotGiven = NOT_GIVEN, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + id: str | Omit = omit, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Channel]: """Returns a paginated list of channels. @@ -123,16 +123,16 @@ def with_streaming_response(self) -> AsyncChannelsResourceWithStreamingResponse: def list( self, *, - id: str | NotGiven = NOT_GIVEN, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + id: str | Omit = omit, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Channel, AsyncEntriesCursor[Channel]]: """Returns a paginated list of channels. diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index 0fb746b..2714d58 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -7,7 +7,7 @@ import httpx from ..types import commit_list_params, commit_commit_all_params, commit_promote_all_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -56,7 +56,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Commit: """ Retrieve a single commit by its ID. @@ -84,19 +84,19 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - promoted: bool | NotGiven = NOT_GIVEN, - resource_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + promoted: bool | Omit = omit, + resource_id: str | Omit = omit, resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] - | NotGiven = NOT_GIVEN, + | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Commit]: """Returns a paginated list of commits in a given environment. @@ -158,13 +158,13 @@ def commit_all( self, *, environment: str, - commit_message: str | NotGiven = NOT_GIVEN, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitCommitAllResponse: """ Commit all changes across all resources in the development environment. @@ -209,7 +209,7 @@ def promote_all( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitPromoteAllResponse: """ Promote all changes across all resources to the target environment from its @@ -256,7 +256,7 @@ def promote_one( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitPromoteOneResponse: """ Promotes one change to the subsequent environment. @@ -310,7 +310,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Commit: """ Retrieve a single commit by its ID. @@ -338,19 +338,19 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - promoted: bool | NotGiven = NOT_GIVEN, - resource_id: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: str | Omit = omit, + limit: int | Omit = omit, + promoted: bool | Omit = omit, + resource_id: str | Omit = omit, resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] - | NotGiven = NOT_GIVEN, + | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Commit, AsyncEntriesCursor[Commit]]: """Returns a paginated list of commits in a given environment. @@ -412,13 +412,13 @@ async def commit_all( self, *, environment: str, - commit_message: str | NotGiven = NOT_GIVEN, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitCommitAllResponse: """ Commit all changes across all resources in the development environment. @@ -463,7 +463,7 @@ async def promote_all( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitPromoteAllResponse: """ Promote all changes across all resources to the target environment from its @@ -510,7 +510,7 @@ async def promote_one( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> CommitPromoteOneResponse: """ Promotes one change to the subsequent environment. diff --git a/src/knock_mapi/resources/email_layouts.py b/src/knock_mapi/resources/email_layouts.py index d527bf9..e9b34f5 100644 --- a/src/knock_mapi/resources/email_layouts.py +++ b/src/knock_mapi/resources/email_layouts.py @@ -10,7 +10,7 @@ email_layout_retrieve_params, email_layout_validate_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -54,14 +54,14 @@ def retrieve( email_layout_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayout: """ Retrieve an email layout by its key, in a given environment. @@ -107,17 +107,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[EmailLayout]: """ Returns a paginated list of email layouts available in a given environment. @@ -173,15 +173,15 @@ def upsert( *, environment: str, email_layout: email_layout_upsert_params.EmailLayout, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayoutUpsertResponse: """ Updates an email layout, or creates a new one if it does not yet exist. @@ -241,7 +241,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayoutValidateResponse: """ Validates an email layout payload without persisting it. @@ -306,14 +306,14 @@ async def retrieve( email_layout_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayout: """ Retrieve an email layout by its key, in a given environment. @@ -359,17 +359,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[EmailLayout, AsyncEntriesCursor[EmailLayout]]: """ Returns a paginated list of email layouts available in a given environment. @@ -425,15 +425,15 @@ async def upsert( *, environment: str, email_layout: email_layout_upsert_params.EmailLayout, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayoutUpsertResponse: """ Updates an email layout, or creates a new one if it does not yet exist. @@ -495,7 +495,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> EmailLayoutValidateResponse: """ Validates an email layout payload without persisting it. diff --git a/src/knock_mapi/resources/environments.py b/src/knock_mapi/resources/environments.py index 4351ac5..09dbed7 100644 --- a/src/knock_mapi/resources/environments.py +++ b/src/knock_mapi/resources/environments.py @@ -5,7 +5,7 @@ import httpx from ..types import environment_list_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -51,7 +51,7 @@ def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Environment: """ Returns a single environment by the `environment_slug`. @@ -78,15 +78,15 @@ def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Environment]: """Returns a paginated list of environments. @@ -158,7 +158,7 @@ async def retrieve( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Environment: """ Returns a single environment by the `environment_slug`. @@ -185,15 +185,15 @@ async def retrieve( def list( self, *, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Environment, AsyncEntriesCursor[Environment]]: """Returns a paginated list of environments. diff --git a/src/knock_mapi/resources/guides.py b/src/knock_mapi/resources/guides.py index ee5b5d8..61b868d 100644 --- a/src/knock_mapi/resources/guides.py +++ b/src/knock_mapi/resources/guides.py @@ -15,7 +15,7 @@ guide_retrieve_params, guide_validate_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import required_args, maybe_transform, async_maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -60,14 +60,14 @@ def retrieve( guide_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Guide: """ Get a guide by its key. @@ -113,17 +113,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Guide]: """ Returns a paginated list of guides available in a given environment. @@ -185,7 +185,7 @@ def activate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: """Activates (or deactivates) a guide in a given environment. @@ -216,14 +216,14 @@ def activate( guide_key: str, *, environment: str, - from_: Union[str, datetime] | NotGiven = NOT_GIVEN, - until: Union[str, datetime] | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | Omit = omit, + until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: """Activates (or deactivates) a guide in a given environment. @@ -258,15 +258,15 @@ def activate( guide_key: str, *, environment: str, - status: bool | NotGiven = NOT_GIVEN, - from_: Union[str, datetime] | NotGiven = NOT_GIVEN, - until: Union[str, datetime] | NotGiven = NOT_GIVEN, + status: bool | Omit = omit, + from_: Union[str, datetime] | Omit = omit, + until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: if not guide_key: raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") @@ -296,15 +296,15 @@ def upsert( *, environment: str, guide: guide_upsert_params.Guide, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideUpsertResponse: """ Updates a guide of a given key, or creates a new one if it does not yet exist. @@ -364,7 +364,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideValidateResponse: """ Validates a guide payload without persisting it. @@ -425,14 +425,14 @@ async def retrieve( guide_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Guide: """ Get a guide by its key. @@ -478,17 +478,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Guide, AsyncEntriesCursor[Guide]]: """ Returns a paginated list of guides available in a given environment. @@ -550,7 +550,7 @@ async def activate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: """Activates (or deactivates) a guide in a given environment. @@ -581,14 +581,14 @@ async def activate( guide_key: str, *, environment: str, - from_: Union[str, datetime] | NotGiven = NOT_GIVEN, - until: Union[str, datetime] | NotGiven = NOT_GIVEN, + from_: Union[str, datetime] | Omit = omit, + until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: """Activates (or deactivates) a guide in a given environment. @@ -623,15 +623,15 @@ async def activate( guide_key: str, *, environment: str, - status: bool | NotGiven = NOT_GIVEN, - from_: Union[str, datetime] | NotGiven = NOT_GIVEN, - until: Union[str, datetime] | NotGiven = NOT_GIVEN, + status: bool | Omit = omit, + from_: Union[str, datetime] | Omit = omit, + until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideActivateResponse: if not guide_key: raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") @@ -663,15 +663,15 @@ async def upsert( *, environment: str, guide: guide_upsert_params.Guide, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideUpsertResponse: """ Updates a guide of a given key, or creates a new one if it does not yet exist. @@ -731,7 +731,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> GuideValidateResponse: """ Validates a guide payload without persisting it. diff --git a/src/knock_mapi/resources/message_types.py b/src/knock_mapi/resources/message_types.py index 8abff16..e345e85 100644 --- a/src/knock_mapi/resources/message_types.py +++ b/src/knock_mapi/resources/message_types.py @@ -10,7 +10,7 @@ message_type_retrieve_params, message_type_validate_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -54,14 +54,14 @@ def retrieve( message_type_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageType: """ Retrieve a message type by its key, in a given environment. @@ -107,17 +107,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[MessageType]: """ Returns a paginated list of message types available in a given environment. @@ -173,15 +173,15 @@ def upsert( *, environment: str, message_type: message_type_upsert_params.MessageType, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageTypeUpsertResponse: """ Updates a message type, or creates a new one if it does not yet exist. @@ -241,7 +241,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageTypeValidateResponse: """ Validates a message type payload without persisting it. @@ -307,14 +307,14 @@ async def retrieve( message_type_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageType: """ Retrieve a message type by its key, in a given environment. @@ -360,17 +360,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[MessageType, AsyncEntriesCursor[MessageType]]: """ Returns a paginated list of message types available in a given environment. @@ -426,15 +426,15 @@ async def upsert( *, environment: str, message_type: message_type_upsert_params.MessageType, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageTypeUpsertResponse: """ Updates a message type, or creates a new one if it does not yet exist. @@ -496,7 +496,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageTypeValidateResponse: """ Validates a message type payload without persisting it. diff --git a/src/knock_mapi/resources/partials.py b/src/knock_mapi/resources/partials.py index 5395a36..6744e3d 100644 --- a/src/knock_mapi/resources/partials.py +++ b/src/knock_mapi/resources/partials.py @@ -5,7 +5,7 @@ import httpx from ..types import partial_list_params, partial_upsert_params, partial_retrieve_params, partial_validate_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -49,14 +49,14 @@ def retrieve( partial_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Partial: """ Get a partial by its key. @@ -102,17 +102,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Partial]: """ List all partials for a given environment. @@ -168,15 +168,15 @@ def upsert( *, environment: str, partial: partial_upsert_params.Partial, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PartialUpsertResponse: """ Updates a partial of a given key, or creates a new one if it does not yet exist. @@ -236,7 +236,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PartialValidateResponse: """ Validates a partial payload without persisting it. @@ -297,14 +297,14 @@ async def retrieve( partial_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Partial: """ Get a partial by its key. @@ -350,17 +350,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Partial, AsyncEntriesCursor[Partial]]: """ List all partials for a given environment. @@ -416,15 +416,15 @@ async def upsert( *, environment: str, partial: partial_upsert_params.Partial, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PartialUpsertResponse: """ Updates a partial of a given key, or creates a new one if it does not yet exist. @@ -484,7 +484,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> PartialValidateResponse: """ Validates a partial payload without persisting it. diff --git a/src/knock_mapi/resources/translations.py b/src/knock_mapi/resources/translations.py index 1df7087..ba685fd 100644 --- a/src/knock_mapi/resources/translations.py +++ b/src/knock_mapi/resources/translations.py @@ -12,7 +12,7 @@ translation_retrieve_params, translation_validate_params, ) -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -57,16 +57,16 @@ def retrieve( locale_code: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - namespace: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + format: Literal["json", "po"] | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + namespace: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationRetrieveResponse: """ Retrieve a translation by its locale and namespace, in a given environment. @@ -119,20 +119,20 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - locale_code: str | NotGiven = NOT_GIVEN, - namespace: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + format: Literal["json", "po"] | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + limit: int | Omit = omit, + locale_code: str | Omit = omit, + namespace: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Translation]: """Returns a paginated list of translations available in a given environment. @@ -201,16 +201,16 @@ def upsert( environment: str, namespace: str, translation: translation_upsert_params.Translation, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: str | Omit = omit, + format: Literal["json", "po"] | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationUpsertResponse: """ Updates a translation of a given locale code + namespace, or creates a new one @@ -280,7 +280,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationValidateResponse: """ Validates a translation payload without persisting it. @@ -345,16 +345,16 @@ async def retrieve( locale_code: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - namespace: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + format: Literal["json", "po"] | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + namespace: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationRetrieveResponse: """ Retrieve a translation by its locale and namespace, in a given environment. @@ -407,20 +407,20 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, - locale_code: str | NotGiven = NOT_GIVEN, - namespace: str | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + format: Literal["json", "po"] | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + limit: int | Omit = omit, + locale_code: str | Omit = omit, + namespace: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Translation, AsyncEntriesCursor[Translation]]: """Returns a paginated list of translations available in a given environment. @@ -489,16 +489,16 @@ async def upsert( environment: str, namespace: str, translation: translation_upsert_params.Translation, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, - format: Literal["json", "po"] | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: str | Omit = omit, + format: Literal["json", "po"] | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationUpsertResponse: """ Updates a translation of a given locale code + namespace, or creates a new one @@ -570,7 +570,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> TranslationValidateResponse: """ Validates a translation payload without persisting it. diff --git a/src/knock_mapi/resources/variables.py b/src/knock_mapi/resources/variables.py index a211ac9..8f542f1 100644 --- a/src/knock_mapi/resources/variables.py +++ b/src/knock_mapi/resources/variables.py @@ -5,7 +5,7 @@ import httpx from ..types import variable_list_params -from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform from .._compat import cached_property from .._resource import SyncAPIResource, AsyncAPIResource @@ -46,15 +46,15 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Variable]: """ Returns a paginated list of variables for a given environment. @@ -122,15 +122,15 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + before: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Variable, AsyncEntriesCursor[Variable]]: """ Returns a paginated list of variables for a given environment. diff --git a/src/knock_mapi/resources/workflows/steps.py b/src/knock_mapi/resources/workflows/steps.py index a3306d9..f93ec3a 100644 --- a/src/knock_mapi/resources/workflows/steps.py +++ b/src/knock_mapi/resources/workflows/steps.py @@ -6,7 +6,7 @@ import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 @@ -50,15 +50,15 @@ def preview_template( workflow_key: str, environment: str, recipient: step_preview_template_params.Recipient, - actor: Optional[step_preview_template_params.Actor] | NotGiven = NOT_GIVEN, - data: Dict[str, object] | NotGiven = NOT_GIVEN, - tenant: Optional[str] | NotGiven = NOT_GIVEN, + actor: Optional[step_preview_template_params.Actor] | Omit = omit, + data: Dict[str, object] | Omit = omit, + tenant: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> StepPreviewTemplateResponse: """ Generates a rendered template for a given channel step in a workflow. @@ -139,15 +139,15 @@ async def preview_template( workflow_key: str, environment: str, recipient: step_preview_template_params.Recipient, - actor: Optional[step_preview_template_params.Actor] | NotGiven = NOT_GIVEN, - data: Dict[str, object] | NotGiven = NOT_GIVEN, - tenant: Optional[str] | NotGiven = NOT_GIVEN, + actor: Optional[step_preview_template_params.Actor] | Omit = omit, + data: Dict[str, object] | Omit = omit, + tenant: Optional[str] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> StepPreviewTemplateResponse: """ Generates a rendered template for a given channel step in a workflow. diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index d9a0e86..83c8ba6 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -22,7 +22,7 @@ workflow_retrieve_params, workflow_validate_params, ) -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -72,14 +72,14 @@ def retrieve( workflow_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Workflow: """ Retrieve a workflow by its key in a given environment. @@ -125,17 +125,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncEntriesCursor[Workflow]: """Returns a paginated list of workflows available in a given environment. @@ -198,7 +198,7 @@ def activate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowActivateResponse: """Activates (or deactivates) a workflow in a given environment. @@ -243,16 +243,16 @@ def run( *, environment: str, recipients: SequenceNotStr[workflow_run_params.Recipient], - actor: Optional[workflow_run_params.Actor] | NotGiven = NOT_GIVEN, - cancellation_key: Optional[str] | NotGiven = NOT_GIVEN, - data: Dict[str, object] | NotGiven = NOT_GIVEN, - tenant: str | NotGiven = NOT_GIVEN, + actor: Optional[workflow_run_params.Actor] | Omit = omit, + cancellation_key: Optional[str] | Omit = omit, + data: Dict[str, object] | Omit = omit, + tenant: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowRunResponse: """ Runs the latest version of a committed workflow in a given environment using the @@ -310,15 +310,15 @@ def upsert( *, environment: str, workflow: workflow_upsert_params.Workflow, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowUpsertResponse: """ Updates a workflow of a given key, or creates a new one if it does not yet @@ -379,7 +379,7 @@ def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowValidateResponse: """Validates a workflow payload without persisting it. @@ -446,14 +446,14 @@ async def retrieve( workflow_key: str, *, environment: str, - annotate: bool | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> Workflow: """ Retrieve a workflow by its key in a given environment. @@ -499,17 +499,17 @@ def list( self, *, environment: str, - after: str | NotGiven = NOT_GIVEN, - annotate: bool | NotGiven = NOT_GIVEN, - before: str | NotGiven = NOT_GIVEN, - hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN, - limit: int | NotGiven = NOT_GIVEN, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[Workflow, AsyncEntriesCursor[Workflow]]: """Returns a paginated list of workflows available in a given environment. @@ -572,7 +572,7 @@ async def activate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowActivateResponse: """Activates (or deactivates) a workflow in a given environment. @@ -619,16 +619,16 @@ async def run( *, environment: str, recipients: SequenceNotStr[workflow_run_params.Recipient], - actor: Optional[workflow_run_params.Actor] | NotGiven = NOT_GIVEN, - cancellation_key: Optional[str] | NotGiven = NOT_GIVEN, - data: Dict[str, object] | NotGiven = NOT_GIVEN, - tenant: str | NotGiven = NOT_GIVEN, + actor: Optional[workflow_run_params.Actor] | Omit = omit, + cancellation_key: Optional[str] | Omit = omit, + data: Dict[str, object] | Omit = omit, + tenant: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowRunResponse: """ Runs the latest version of a committed workflow in a given environment using the @@ -686,15 +686,15 @@ async def upsert( *, environment: str, workflow: workflow_upsert_params.Workflow, - annotate: bool | NotGiven = NOT_GIVEN, - commit: bool | NotGiven = NOT_GIVEN, - commit_message: str | NotGiven = NOT_GIVEN, + annotate: bool | Omit = omit, + commit: bool | Omit = omit, + commit_message: 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, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowUpsertResponse: """ Updates a workflow of a given key, or creates a new one if it does not yet @@ -755,7 +755,7 @@ async def validate( extra_headers: Headers | None = None, extra_query: Query | None = None, extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> WorkflowValidateResponse: """Validates a workflow payload without persisting it. diff --git a/tests/test_transform.py b/tests/test_transform.py index c3a7563..d019655 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -8,7 +8,7 @@ import pytest -from knock_mapi._types import NOT_GIVEN, Base64FileInput +from knock_mapi._types import Base64FileInput, omit, not_given from knock_mapi._utils import ( PropertyInfo, transform as _transform, @@ -450,4 +450,11 @@ async def test_transform_skipping(use_async: bool) -> None: @pytest.mark.asyncio async def test_strips_notgiven(use_async: bool) -> None: assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} - assert await transform({"foo_bar": NOT_GIVEN}, Foo1, use_async) == {} + assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} + + +@parametrize +@pytest.mark.asyncio +async def test_strips_omit(use_async: bool) -> None: + assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} + assert await transform({"foo_bar": omit}, Foo1, use_async) == {} From 47f30baf8a98c54137ee207d0e91c9dd0e271cc4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 17:45:20 +0000 Subject: [PATCH 061/101] chore: do not install brew dependencies in ./scripts/bootstrap by default --- scripts/bootstrap | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index e84fe62..b430fee 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,10 +4,18 @@ set -e cd "$(dirname "$0")/.." -if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { - echo "==> Installing Homebrew dependencies…" - brew bundle + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo } fi From c08046dd8dca83f69eb0b3c4ab6eef57a88ac963 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:10:34 +0000 Subject: [PATCH 062/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/commits.py | 8 ++++++-- src/knock_mapi/types/commit.py | 2 +- src/knock_mapi/types/commit_list_params.py | 4 +++- tests/api_resources/test_commits.py | 4 ++-- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8ef95c3..2bd4c75 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b90dac2a045de60a7d3f873aa4e800f236a9800b15b553fd0b62318193dab8fb.yml -openapi_spec_hash: 61d2dd8fc14bd2c53af4d764d42cf9bd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-f8fe62dc486d74a5ade58618f4f4316cb7ee49cec2caa53f36412201b51f7a7f.yml +openapi_spec_hash: 0bf7d569a84420604758c132c1dd06ac config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index 2714d58..aafd0f9 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -89,7 +89,9 @@ def list( limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, - resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + resource_type: Literal[ + "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + ] | 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. @@ -343,7 +345,9 @@ def list( limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, - resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + resource_type: Literal[ + "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + ] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/knock_mapi/types/commit.py b/src/knock_mapi/types/commit.py index 9203a4f..245ac96 100644 --- a/src/knock_mapi/types/commit.py +++ b/src/knock_mapi/types/commit.py @@ -21,7 +21,7 @@ class Resource(BaseModel): identifier: str """The unique identifier for the resource.""" - type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + type: Literal["dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"] """The type of the resource object.""" diff --git a/src/knock_mapi/types/commit_list_params.py b/src/knock_mapi/types/commit_list_params.py index ecab01d..26a8ad5 100644 --- a/src/knock_mapi/types/commit_list_params.py +++ b/src/knock_mapi/types/commit_list_params.py @@ -34,5 +34,7 @@ class CommitListParams(TypedDict, total=False): namespace, separated by a `/`. For example, `en/courses` or `en`. """ - resource_type: Literal["email_layout", "guide", "message_type", "partial", "translation", "workflow"] + resource_type: Literal[ + "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + ] """Filter commits by resource type. Must be used together with resource_id.""" diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 335f771..b20ac1c 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -83,7 +83,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: limit=0, promoted=True, resource_id="resource_id", - resource_type="email_layout", + resource_type="dynamic_audience", ) assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) @@ -298,7 +298,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - limit=0, promoted=True, resource_id="resource_id", - resource_type="email_layout", + resource_type="dynamic_audience", ) assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) From 068056627b37ad3595d1f35949525c17849351fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:55:10 +0000 Subject: [PATCH 063/101] chore(internal): improve examples --- tests/api_resources/test_workflows.py | 340 ++++++++++++++++++++++++-- 1 file changed, 320 insertions(+), 20 deletions(-) diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 2c930ae..bccce21 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -253,7 +253,14 @@ def test_method_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) @@ -266,7 +273,54 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": { + "bcc_address": None, + "cc_address": None, + "from_address": "hello@example.com", + "from_name": "John Doe", + "json_overrides": '{"some_override": true}', + "link_tracking": True, + "open_tracking": True, + "reply_to_address": None, + "to_address": "hello@example.com", + }, + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], "categories": ["string"], "conditions": { "all": [ @@ -299,7 +353,14 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -316,7 +377,14 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) as response: assert not response.is_closed @@ -336,7 +404,14 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -348,7 +423,14 @@ def test_method_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) @@ -361,7 +443,54 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": { + "bcc_address": None, + "cc_address": None, + "from_address": "hello@example.com", + "from_name": "John Doe", + "json_overrides": '{"some_override": true}', + "link_tracking": True, + "open_tracking": True, + "reply_to_address": None, + "to_address": "hello@example.com", + }, + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], "categories": ["string"], "conditions": { "all": [ @@ -391,7 +520,14 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -408,7 +544,14 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) as response: assert not response.is_closed @@ -428,7 +571,14 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -667,7 +817,14 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) assert_matches_type(WorkflowUpsertResponse, workflow, path=["response"]) @@ -680,7 +837,54 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": { + "bcc_address": None, + "cc_address": None, + "from_address": "hello@example.com", + "from_name": "John Doe", + "json_overrides": '{"some_override": true}', + "link_tracking": True, + "open_tracking": True, + "reply_to_address": None, + "to_address": "hello@example.com", + }, + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], "categories": ["string"], "conditions": { "all": [ @@ -713,7 +917,14 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -730,7 +941,14 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) as response: assert not response.is_closed @@ -750,7 +968,14 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -762,7 +987,14 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) @@ -775,7 +1007,54 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": { + "bcc_address": None, + "cc_address": None, + "from_address": "hello@example.com", + "from_name": "John Doe", + "json_overrides": '{"some_override": true}', + "link_tracking": True, + "open_tracking": True, + "reply_to_address": None, + "to_address": "hello@example.com", + }, + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], "categories": ["string"], "conditions": { "all": [ @@ -805,7 +1084,14 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) @@ -822,7 +1108,14 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) as response: assert not response.is_closed @@ -842,6 +1135,13 @@ async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: environment="development", workflow={ "name": "My Workflow", - "steps": [], + "steps": [ + { + "name": "Channel 1", + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], }, ) From 2e53b16a3636da45f5378470b334f25b37e9bf27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 23:09:14 +0000 Subject: [PATCH 064/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/request_template.py | 20 +++++++++---------- .../types/request_template_param.py | 20 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2bd4c75..8ee5a2e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-f8fe62dc486d74a5ade58618f4f4316cb7ee49cec2caa53f36412201b51f7a7f.yml -openapi_spec_hash: 0bf7d569a84420604758c132c1dd06ac +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-c04deaccc49a6d2d87d407e3c0b7a8a4fe2bf1e1ab86b42d8a3312f6d38b36a8.yml +openapi_spec_hash: 4789b4013d306a488bf63a2287cd88e6 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/request_template.py b/src/knock_mapi/types/request_template.py index 9f420fa..146ed3e 100644 --- a/src/knock_mapi/types/request_template.py +++ b/src/knock_mapi/types/request_template.py @@ -1,14 +1,14 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List, Union, Optional from typing_extensions import Literal from .._models import BaseModel -__all__ = ["RequestTemplate", "Header", "QueryParam"] +__all__ = ["RequestTemplate", "HeadersUnionMember1", "QueryParamsUnionMember1"] -class Header(BaseModel): +class HeadersUnionMember1(BaseModel): key: str """The key of the header.""" @@ -16,7 +16,7 @@ class Header(BaseModel): """The value of the header.""" -class QueryParam(BaseModel): +class QueryParamsUnionMember1(BaseModel): key: str """The key of the query param.""" @@ -34,14 +34,14 @@ class RequestTemplate(BaseModel): body: Optional[str] = None """The body of the request. Only used for POST or PUT requests.""" - headers: Optional[List[Header]] = None - """A list of key-value pairs for the request headers. + headers: Union[str, List[HeadersUnionMember1], None] = None + """The headers of the request. - Each object should contain key and value fields with string values. + Can be a template string or a list of key-value pairs. """ - query_params: Optional[List[QueryParam]] = None - """A list of key-value pairs for the request query params. + query_params: Union[str, List[QueryParamsUnionMember1], None] = None + """The query params of the request. - Each object should contain key and value fields with string values. + Can be a template string or a list of key-value pairs. """ diff --git a/src/knock_mapi/types/request_template_param.py b/src/knock_mapi/types/request_template_param.py index 1d1f46b..d2f4e8c 100644 --- a/src/knock_mapi/types/request_template_param.py +++ b/src/knock_mapi/types/request_template_param.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Iterable, Optional +from typing import Union, Iterable, Optional from typing_extensions import Literal, Required, TypedDict -__all__ = ["RequestTemplateParam", "Header", "QueryParam"] +__all__ = ["RequestTemplateParam", "HeadersUnionMember1", "QueryParamsUnionMember1"] -class Header(TypedDict, total=False): +class HeadersUnionMember1(TypedDict, total=False): key: Required[str] """The key of the header.""" @@ -16,7 +16,7 @@ class Header(TypedDict, total=False): """The value of the header.""" -class QueryParam(TypedDict, total=False): +class QueryParamsUnionMember1(TypedDict, total=False): key: Required[str] """The key of the query param.""" @@ -34,14 +34,14 @@ class RequestTemplateParam(TypedDict, total=False): body: Optional[str] """The body of the request. Only used for POST or PUT requests.""" - headers: Iterable[Header] - """A list of key-value pairs for the request headers. + headers: Union[str, Iterable[HeadersUnionMember1]] + """The headers of the request. - Each object should contain key and value fields with string values. + Can be a template string or a list of key-value pairs. """ - query_params: Iterable[QueryParam] - """A list of key-value pairs for the request query params. + query_params: Union[str, Iterable[QueryParamsUnionMember1]] + """The query params of the request. - Each object should contain key and value fields with string values. + Can be a template string or a list of key-value pairs. """ From e44de16209fbd7c8fadcbb6478ef216b887bc8d7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 14:46:16 +0000 Subject: [PATCH 065/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/commit.py | 13 +++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8ee5a2e..5fc053c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-c04deaccc49a6d2d87d407e3c0b7a8a4fe2bf1e1ab86b42d8a3312f6d38b36a8.yml -openapi_spec_hash: 4789b4013d306a488bf63a2287cd88e6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-1fc58f1dffc84763eda45a6699fd1cdf527e83ca036e5cfd580e6d2c1845420f.yml +openapi_spec_hash: 48e0dea355ccd468ec4d74887f6463bc config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/commit.py b/src/knock_mapi/types/commit.py index 245ac96..a66133b 100644 --- a/src/knock_mapi/types/commit.py +++ b/src/knock_mapi/types/commit.py @@ -6,10 +6,10 @@ from .._models import BaseModel -__all__ = ["Commit", "CommitAuthor", "Resource"] +__all__ = ["Commit", "Author", "Resource"] -class CommitAuthor(BaseModel): +class Author(BaseModel): email: str """The email address of the commit author.""" @@ -29,12 +29,9 @@ class Commit(BaseModel): id: str """The unique identifier for the commit.""" - commit_author: CommitAuthor + author: Author """The author of the commit.""" - commit_message: str - """The optional message about the commit.""" - created_at: datetime """The timestamp of when the commit was created.""" @@ -44,5 +41,5 @@ class Commit(BaseModel): resource: Resource """The resource object associated with the commit.""" - updated_at: datetime - """The timestamp of when the commit was last updated.""" + commit_message: Optional[str] = None + """The optional message about the commit.""" From 4416f123258f4b2ab0bebc6c2f17297b9bb04bcc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 21:25:32 +0000 Subject: [PATCH 066/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/channel_group_rule.py | 1 + src/knock_mapi/types/condition.py | 1 + src/knock_mapi/types/condition_param.py | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5fc053c..6014dca 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-1fc58f1dffc84763eda45a6699fd1cdf527e83ca036e5cfd580e6d2c1845420f.yml -openapi_spec_hash: 48e0dea355ccd468ec4d74887f6463bc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b8c7c19a7063f4e93a91191e053cefbc49e8af420aba5702d2658d432f72f3f2.yml +openapi_spec_hash: a58274334b5ff0ca806252e31d286dac config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/channel_group_rule.py b/src/knock_mapi/types/channel_group_rule.py index 993120f..aba7941 100644 --- a/src/knock_mapi/types/channel_group_rule.py +++ b/src/knock_mapi/types/channel_group_rule.py @@ -43,6 +43,7 @@ class ChannelGroupRule(BaseModel): "contains", "not_contains", "contains_all", + "not_contains_all", "empty", "not_empty", "is_audience_member", diff --git a/src/knock_mapi/types/condition.py b/src/knock_mapi/types/condition.py index b5ee704..bc6d571 100644 --- a/src/knock_mapi/types/condition.py +++ b/src/knock_mapi/types/condition.py @@ -19,6 +19,7 @@ class Condition(BaseModel): "contains", "not_contains", "contains_all", + "not_contains_all", "empty", "not_empty", "is_audience_member", diff --git a/src/knock_mapi/types/condition_param.py b/src/knock_mapi/types/condition_param.py index ad44a1a..db65a04 100644 --- a/src/knock_mapi/types/condition_param.py +++ b/src/knock_mapi/types/condition_param.py @@ -20,6 +20,7 @@ class ConditionParam(TypedDict, total=False): "contains", "not_contains", "contains_all", + "not_contains_all", "empty", "not_empty", "is_audience_member", From 39d08bb5ee700407596d84b9b73e52b38c5ac76b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:49:03 +0000 Subject: [PATCH 067/101] chore(internal): detect missing future annotations with ruff --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 581c63e..8ad1d3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -224,6 +224,8 @@ select = [ "B", # remove unused imports "F401", + # check for missing future annotations + "FA102", # bare except statements "E722", # unused arguments @@ -246,6 +248,8 @@ unfixable = [ "T203", ] +extend-safe-fixes = ["FA102"] + [tool.ruff.lint.flake8-tidy-imports.banned-api] "functools.lru_cache".msg = "This function does not retain type information for the wrapped function's arguments; The `lru_cache` function from `_utils` should be used instead" From 72a6e7f4c68c3cf1a755f3a6953cb79c3c63ac53 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:39:20 +0000 Subject: [PATCH 068/101] feat(api): api update --- .stats.yml | 4 +- api.md | 3 +- .../resources/workflows/workflows.py | 9 +- src/knock_mapi/types/__init__.py | 4 + .../types/workflow_retrieve_response.py | 130 ++++++++++++++++++ tests/api_resources/test_workflows.py | 17 +-- 6 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 src/knock_mapi/types/workflow_retrieve_response.py diff --git a/.stats.yml b/.stats.yml index 6014dca..a1058df 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-b8c7c19a7063f4e93a91191e053cefbc49e8af420aba5702d2658d432f72f3f2.yml -openapi_spec_hash: a58274334b5ff0ca806252e31d286dac +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-0d16b5986d75d9481f8ca2578b7aa5bb3bfc1c2e59821347bebe233221f2d082.yml +openapi_spec_hash: 3dcaa614e2a4d51a732749d15573f7e7 config_hash: f9e83854b42d2264516f449568348afa diff --git a/api.md b/api.md index f48b15f..440f5a6 100644 --- a/api.md +++ b/api.md @@ -110,6 +110,7 @@ from knock_mapi.types import ( WorkflowStep, WorkflowThrottleStep, WorkflowTriggerWorkflowStep, + WorkflowRetrieveResponse, WorkflowActivateResponse, WorkflowRunResponse, WorkflowUpsertResponse, @@ -119,7 +120,7 @@ from knock_mapi.types import ( Methods: -- client.workflows.retrieve(workflow_key, \*\*params) -> Workflow +- client.workflows.retrieve(workflow_key, \*\*params) -> WorkflowRetrieveResponse - client.workflows.list(\*\*params) -> SyncEntriesCursor[Workflow] - client.workflows.activate(workflow_key, \*\*params) -> WorkflowActivateResponse - client.workflows.run(workflow_key, \*\*params) -> WorkflowRunResponse diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index 83c8ba6..98619a9 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -38,6 +38,7 @@ from ...types.workflow_run_response import WorkflowRunResponse from ...types.workflow_upsert_response import WorkflowUpsertResponse from ...types.workflow_activate_response import WorkflowActivateResponse +from ...types.workflow_retrieve_response import WorkflowRetrieveResponse from ...types.workflow_validate_response import WorkflowValidateResponse __all__ = ["WorkflowsResource", "AsyncWorkflowsResource"] @@ -80,7 +81,7 @@ def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Workflow: + ) -> WorkflowRetrieveResponse: """ Retrieve a workflow by its key in a given environment. @@ -118,7 +119,7 @@ def retrieve( workflow_retrieve_params.WorkflowRetrieveParams, ), ), - cast_to=Workflow, + cast_to=WorkflowRetrieveResponse, ) def list( @@ -454,7 +455,7 @@ async def retrieve( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> Workflow: + ) -> WorkflowRetrieveResponse: """ Retrieve a workflow by its key in a given environment. @@ -492,7 +493,7 @@ async def retrieve( workflow_retrieve_params.WorkflowRetrieveParams, ), ), - cast_to=Workflow, + cast_to=WorkflowRetrieveResponse, ) def list( diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 8b232f2..5f274b8 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -7,6 +7,7 @@ workflow_branch_step, workflow_upsert_response, workflow_activate_response, + workflow_retrieve_response, workflow_validate_response, ) from .. import _compat @@ -107,6 +108,7 @@ from .sms_channel_settings_param import SMSChannelSettingsParam as SMSChannelSettingsParam from .workflow_activate_response import WorkflowActivateResponse as WorkflowActivateResponse from .workflow_branch_step_param import WorkflowBranchStepParam as WorkflowBranchStepParam +from .workflow_retrieve_response import WorkflowRetrieveResponse as WorkflowRetrieveResponse from .workflow_validate_response import WorkflowValidateResponse as WorkflowValidateResponse from .chat_channel_settings_param import ChatChannelSettingsParam as ChatChannelSettingsParam from .commit_promote_all_response import CommitPromoteAllResponse as CommitPromoteAllResponse @@ -141,12 +143,14 @@ if _compat.PYDANTIC_V1: workflow.Workflow.update_forward_refs() # type: ignore workflow_branch_step.WorkflowBranchStep.update_forward_refs() # type: ignore + workflow_retrieve_response.WorkflowRetrieveResponse.update_forward_refs() # type: ignore workflow_activate_response.WorkflowActivateResponse.update_forward_refs() # type: ignore workflow_upsert_response.WorkflowUpsertResponse.update_forward_refs() # type: ignore workflow_validate_response.WorkflowValidateResponse.update_forward_refs() # type: ignore else: workflow.Workflow.model_rebuild(_parent_namespace_depth=0) workflow_branch_step.WorkflowBranchStep.model_rebuild(_parent_namespace_depth=0) + workflow_retrieve_response.WorkflowRetrieveResponse.model_rebuild(_parent_namespace_depth=0) workflow_activate_response.WorkflowActivateResponse.model_rebuild(_parent_namespace_depth=0) workflow_upsert_response.WorkflowUpsertResponse.model_rebuild(_parent_namespace_depth=0) workflow_validate_response.WorkflowValidateResponse.model_rebuild(_parent_namespace_depth=0) diff --git a/src/knock_mapi/types/workflow_retrieve_response.py b/src/knock_mapi/types/workflow_retrieve_response.py new file mode 100644 index 0000000..052d85b --- /dev/null +++ b/src/knock_mapi/types/workflow_retrieve_response.py @@ -0,0 +1,130 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel +from .condition_group import ConditionGroup + +__all__ = ["WorkflowRetrieveResponse", "CreatedBy", "Settings", "UpdatedBy"] + + +class CreatedBy(BaseModel): + id: str + """The user's unique identifier.""" + + email: str + """The user's email address.""" + + name: Optional[str] = None + """The user's name.""" + + +class Settings(BaseModel): + is_commercial: Optional[bool] = None + """Whether the workflow is commercial. Defaults to false.""" + + override_preferences: Optional[bool] = None + """Whether to ignore recipient preferences for a given type of notification. + + If true, will send for every channel in the workflow even if the recipient has + opted out of a certain kind. Defaults to false. + """ + + +class UpdatedBy(BaseModel): + id: str + """The user's unique identifier.""" + + email: str + """The user's email address.""" + + name: Optional[str] = None + """The user's name.""" + + +class WorkflowRetrieveResponse(BaseModel): + active: bool + """ + Whether the workflow is + [active](https://docs.knock.app/concepts/workflows#workflow-status) in the + current environment. (read-only). + """ + + created_at: datetime + """The timestamp of when the workflow was created. (read-only).""" + + environment: str + """The slug of the environment in which the workflow exists. (read-only).""" + + key: str + """The unique key string for the workflow object. + + Must be at minimum 3 characters and at maximum 255 characters in length. Must be + in the format of ^[a-z0-9_-]+$. + """ + + name: str + """A name for the workflow. Must be at maximum 255 characters in length.""" + + sha: str + """The SHA hash of the workflow data. (read-only).""" + + steps: List["WorkflowStep"] + """A list of workflow step objects in the workflow.""" + + updated_at: datetime + """The timestamp of when the workflow was last updated. (read-only).""" + + valid: bool + """Whether the workflow and its steps are in a valid state. (read-only).""" + + categories: Optional[List[str]] = None + """ + A list of + [categories](https://docs.knock.app/concepts/workflows#workflow-categories) that + the workflow belongs to. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + created_by: Optional[CreatedBy] = None + """User information.""" + + deleted_at: Optional[datetime] = None + """The timestamp of when the workflow was deleted. (read-only).""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow object. + + Useful for adding notes about the workflow for internal purposes. Maximum of 280 + characters allowed. + """ + + settings: Optional[Settings] = None + """A map of workflow settings.""" + + trigger_data_json_schema: Optional[Dict[str, object]] = None + """A JSON schema for the expected structure of the workflow trigger's data payload. + + Used to validate trigger requests. Read more in the + [docs](https://docs.knock.app/developer-tools/validating-trigger-data). + """ + + trigger_frequency: Optional[Literal["every_trigger", "once_per_recipient", "once_per_recipient_per_tenant"]] = None + """The frequency at which the workflow should be triggered. + + One of: `once_per_recipient`, `once_per_recipient_per_tenant`, `every_trigger`. + Defaults to `every_trigger`. Read more in + [docs](https://docs.knock.app/send-notifications/triggering-workflows/overview#controlling-workflow-trigger-frequency). + """ + + updated_by: Optional[UpdatedBy] = None + """User information.""" + + +from .workflow_step import WorkflowStep diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index bccce21..8db495b 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -14,6 +14,7 @@ WorkflowRunResponse, WorkflowUpsertResponse, WorkflowActivateResponse, + WorkflowRetrieveResponse, WorkflowValidateResponse, ) from knock_mapi.pagination import SyncEntriesCursor, AsyncEntriesCursor @@ -31,7 +32,7 @@ def test_method_retrieve(self, client: KnockMgmt) -> None: workflow_key="workflow_key", environment="development", ) - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -42,7 +43,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: annotate=True, hide_uncommitted_changes=True, ) - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -55,7 +56,7 @@ def test_raw_response_retrieve(self, client: KnockMgmt) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" workflow = response.parse() - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -68,7 +69,7 @@ def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" workflow = response.parse() - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) assert cast(Any, response.is_closed) is True @@ -595,7 +596,7 @@ async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: workflow_key="workflow_key", environment="development", ) - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -606,7 +607,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm annotate=True, hide_uncommitted_changes=True, ) - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -619,7 +620,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" workflow = await response.parse() - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize @@ -632,7 +633,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) - assert response.http_request.headers.get("X-Stainless-Lang") == "python" workflow = await response.parse() - assert_matches_type(Workflow, workflow, path=["response"]) + assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) assert cast(Any, response.is_closed) is True From ab44013d8a3f67eee6f5c15e0d580844c7b0a965 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:33:25 +0000 Subject: [PATCH 069/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/commits.py | 4 ++-- src/knock_mapi/types/commit.py | 2 +- src/knock_mapi/types/commit_list_params.py | 4 +--- tests/api_resources/test_commits.py | 4 ++-- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.stats.yml b/.stats.yml index a1058df..7d8b5bf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-0d16b5986d75d9481f8ca2578b7aa5bb3bfc1c2e59821347bebe233221f2d082.yml -openapi_spec_hash: 3dcaa614e2a4d51a732749d15573f7e7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-5bbf44ef22526b2855f95d88af02a38dff8936537927b44bdec78a01fdca0118.yml +openapi_spec_hash: 7eb2ab95d1fcfe07c7f45dc86dfb982c config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index aafd0f9..357b0af 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -90,7 +90,7 @@ def list( promoted: bool | Omit = omit, resource_id: str | Omit = omit, resource_type: Literal[ - "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + "audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" ] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -346,7 +346,7 @@ def list( promoted: bool | Omit = omit, resource_id: str | Omit = omit, resource_type: Literal[ - "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + "audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" ] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/knock_mapi/types/commit.py b/src/knock_mapi/types/commit.py index a66133b..7d90567 100644 --- a/src/knock_mapi/types/commit.py +++ b/src/knock_mapi/types/commit.py @@ -21,7 +21,7 @@ class Resource(BaseModel): identifier: str """The unique identifier for the resource.""" - type: Literal["dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"] + type: Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"] """The type of the resource object.""" diff --git a/src/knock_mapi/types/commit_list_params.py b/src/knock_mapi/types/commit_list_params.py index 26a8ad5..dd785dc 100644 --- a/src/knock_mapi/types/commit_list_params.py +++ b/src/knock_mapi/types/commit_list_params.py @@ -34,7 +34,5 @@ class CommitListParams(TypedDict, total=False): namespace, separated by a `/`. For example, `en/courses` or `en`. """ - resource_type: Literal[ - "dynamic_audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" - ] + resource_type: Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"] """Filter commits by resource type. Must be used together with resource_id.""" diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index b20ac1c..61b8252 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -83,7 +83,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: limit=0, promoted=True, resource_id="resource_id", - resource_type="dynamic_audience", + resource_type="audience", ) assert_matches_type(SyncEntriesCursor[Commit], commit, path=["response"]) @@ -298,7 +298,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - limit=0, promoted=True, resource_id="resource_id", - resource_type="dynamic_audience", + resource_type="audience", ) assert_matches_type(AsyncEntriesCursor[Commit], commit, path=["response"]) From c6c6d98ec14a7429e16a41aa361b5ec94cbca623 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:20:36 +0000 Subject: [PATCH 070/101] chore: bump `httpx-aiohttp` version to 0.1.9 --- pyproject.toml | 2 +- requirements-dev.lock | 2 +- requirements.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8ad1d3e..be26e0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Homepage = "https://github.com/knocklabs/knock-mgmt-python" Repository = "https://github.com/knocklabs/knock-mgmt-python" [project.optional-dependencies] -aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.8"] +aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"] [tool.rye] managed = true diff --git a/requirements-dev.lock b/requirements-dev.lock index 050552d..473acbd 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -56,7 +56,7 @@ httpx==0.28.1 # via httpx-aiohttp # via knock-mapi # via respx -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.9 # via knock-mapi idna==3.4 # via anyio diff --git a/requirements.lock b/requirements.lock index b43763a..d8a610d 100644 --- a/requirements.lock +++ b/requirements.lock @@ -43,7 +43,7 @@ httpcore==1.0.9 httpx==0.28.1 # via httpx-aiohttp # via knock-mapi -httpx-aiohttp==0.1.8 +httpx-aiohttp==0.1.9 # via knock-mapi idna==3.4 # via anyio From 6e33c35c2b5e0e6cd24295edbde61796e6a2f1a3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 19:47:39 +0000 Subject: [PATCH 071/101] feat(api): api update --- .stats.yml | 4 +- src/knock_mapi/types/auth_verify_response.py | 72 +++++++++++++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7d8b5bf..194cab5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-5bbf44ef22526b2855f95d88af02a38dff8936537927b44bdec78a01fdca0118.yml -openapi_spec_hash: 7eb2ab95d1fcfe07c7f45dc86dfb982c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-8553e22cfa971f674db8fc76f54dcfae03b1fcd953419ad75c2a88d12d0fe058.yml +openapi_spec_hash: 388b2fcc4cae6f1b21d07b8cbce06f3b config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/types/auth_verify_response.py b/src/knock_mapi/types/auth_verify_response.py index ce528ed..eaea719 100644 --- a/src/knock_mapi/types/auth_verify_response.py +++ b/src/knock_mapi/types/auth_verify_response.py @@ -5,16 +5,86 @@ from .._models import BaseModel -__all__ = ["AuthVerifyResponse"] +__all__ = ["AuthVerifyResponse", "AccountFeatures"] + + +class AccountFeatures(BaseModel): + batch_items_render_limit_allowed: Optional[bool] = None + """Whether batch rendering limits can be configured.""" + + custom_branding_allowed: Optional[bool] = None + """Whether custom branding can be applied to notifications.""" + + data_retention_days: Optional[int] = None + """Number of days data is retained, null for unlimited retention.""" + + data_warehouse_extension_allowed: Optional[bool] = None + """Whether data warehouse integration extensions are available.""" + + datadog_extension_allowed: Optional[bool] = None + """Whether Datadog integration extension is available.""" + + dsync_allowed: Optional[bool] = None + """Whether directory sync functionality is available.""" + + guides_monthly_notified_recipients_limit: Optional[int] = None + """Monthly limit for guide notification recipients, null for unlimited.""" + + heap_extension_allowed: Optional[bool] = None + """Whether Heap integration extension is available.""" + + knock_branding_required: Optional[bool] = None + """Whether Knock branding is required to be displayed.""" + + litmus_email_preview_allowed: Optional[bool] = None + """Whether Litmus email preview integration is available.""" + + message_sent_limit: Optional[int] = None + """Monthly limit for messages sent, null for unlimited.""" + + new_relic_extension_allowed: Optional[bool] = None + """Whether New Relic integration extension is available.""" + + segment_extension_allowed: Optional[bool] = None + """Whether Segment integration extension is available.""" + + self_serve_allowed: Optional[bool] = None + """Whether self-service account management features are available.""" + + sso_allowed: Optional[bool] = None + """Whether single sign-on (SSO) is enabled for the account.""" + + tenant_preferences_allowed: Optional[bool] = None + """Whether tenant-level preferences are supported.""" + + translations_allowed: Optional[bool] = None + """Whether multi-language translations are supported.""" class AuthVerifyResponse(BaseModel): + account_features: AccountFeatures + """Account plan features and limits.""" + account_name: str + """The display name of the account.""" account_slug: str + """The unique slug identifier for the account.""" type: Literal["service_token", "oauth_context"] + """ + The type of authentication context - either a service token or OAuth user + context. + """ service_token_name: Optional[str] = None + """ + The name of the service token if authenticated via service token, null for OAuth + contexts. + """ user_id: Optional[str] = None + """ + The ID of the authenticated user if in OAuth context, null for service token + contexts. + """ From 83ec5df95b6865f85e0d3ff24eb061e567c87727 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 17:38:39 +0000 Subject: [PATCH 072/101] feat(api): api update --- .stats.yml | 4 +- src/knock_mapi/resources/commits.py | 83 +++++++++++++++++-- .../types/commit_commit_all_params.py | 19 ++++- src/knock_mapi/types/commit_list_params.py | 12 ++- .../types/commit_promote_all_params.py | 19 ++++- tests/api_resources/test_commits.py | 24 ++++++ 6 files changed, 147 insertions(+), 14 deletions(-) diff --git a/.stats.yml b/.stats.yml index 194cab5..c340bbc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-8553e22cfa971f674db8fc76f54dcfae03b1fcd953419ad75c2a88d12d0fe058.yml -openapi_spec_hash: 388b2fcc4cae6f1b21d07b8cbce06f3b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-edf7c2dadb8d5434be9dea2bb70f6d1a52f8aa9754258014ba9716f5a103c65b.yml +openapi_spec_hash: 763acd11ec0b5dbf2301a1cbcf7aac47 config_hash: f9e83854b42d2264516f449568348afa diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index 357b0af..d1253cf 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import List, Union from typing_extensions import Literal import httpx @@ -89,8 +90,9 @@ def list( limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, - resource_type: Literal[ - "audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], ] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -122,7 +124,8 @@ def list( this will be the locale code and namespace, separated by a `/`. For example, `en/courses` or `en`. - resource_type: Filter commits by resource type. Must be used together with resource_id. + resource_type: Filter commits by resource type(s). Accepts a single type or array of types. Can + be combined with resource_id to filter for specific resources. extra_headers: Send extra headers @@ -161,6 +164,12 @@ def commit_all( *, environment: str, commit_message: str | Omit = omit, + resource_id: str | Omit = omit, + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + | 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, @@ -176,6 +185,12 @@ def commit_all( commit_message: An optional message to include in a commit. + resource_id: Filter changes to commit by resource identifier. Must be used together with + resource_type. + + resource_type: Filter changes to commit by resource type(s). Accepts a single type or array of + types. Can be combined with resource_id to filter for specific resources. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -195,6 +210,8 @@ def commit_all( { "environment": environment, "commit_message": commit_message, + "resource_id": resource_id, + "resource_type": resource_type, }, commit_commit_all_params.CommitCommitAllParams, ), @@ -206,6 +223,12 @@ def promote_all( self, *, to_environment: str, + resource_id: str | Omit = omit, + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + | 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, @@ -227,6 +250,12 @@ def promote_all( Note: This must be a non-development environment. + resource_id: Filter commits to promote by resource identifier. Must be used together with + resource_type. + + resource_type: Filter commits to promote by resource type(s). Accepts a single type or array of + types. Can be combined with resource_id to filter for specific resources. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -243,7 +272,12 @@ def promote_all( extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"to_environment": to_environment}, commit_promote_all_params.CommitPromoteAllParams + { + "to_environment": to_environment, + "resource_id": resource_id, + "resource_type": resource_type, + }, + commit_promote_all_params.CommitPromoteAllParams, ), ), cast_to=CommitPromoteAllResponse, @@ -345,8 +379,9 @@ def list( limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, - resource_type: Literal[ - "audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow" + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], ] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -378,7 +413,8 @@ def list( this will be the locale code and namespace, separated by a `/`. For example, `en/courses` or `en`. - resource_type: Filter commits by resource type. Must be used together with resource_id. + resource_type: Filter commits by resource type(s). Accepts a single type or array of types. Can + be combined with resource_id to filter for specific resources. extra_headers: Send extra headers @@ -417,6 +453,12 @@ async def commit_all( *, environment: str, commit_message: str | Omit = omit, + resource_id: str | Omit = omit, + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + | 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, @@ -432,6 +474,12 @@ async def commit_all( commit_message: An optional message to include in a commit. + resource_id: Filter changes to commit by resource identifier. Must be used together with + resource_type. + + resource_type: Filter changes to commit by resource type(s). Accepts a single type or array of + types. Can be combined with resource_id to filter for specific resources. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -451,6 +499,8 @@ async def commit_all( { "environment": environment, "commit_message": commit_message, + "resource_id": resource_id, + "resource_type": resource_type, }, commit_commit_all_params.CommitCommitAllParams, ), @@ -462,6 +512,12 @@ async def promote_all( self, *, to_environment: str, + resource_id: str | Omit = omit, + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + | 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, @@ -483,6 +539,12 @@ async def promote_all( Note: This must be a non-development environment. + resource_id: Filter commits to promote by resource identifier. Must be used together with + resource_type. + + resource_type: Filter commits to promote by resource type(s). Accepts a single type or array of + types. Can be combined with resource_id to filter for specific resources. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -499,7 +561,12 @@ async def promote_all( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"to_environment": to_environment}, commit_promote_all_params.CommitPromoteAllParams + { + "to_environment": to_environment, + "resource_id": resource_id, + "resource_type": resource_type, + }, + commit_promote_all_params.CommitPromoteAllParams, ), ), cast_to=CommitPromoteAllResponse, diff --git a/src/knock_mapi/types/commit_commit_all_params.py b/src/knock_mapi/types/commit_commit_all_params.py index d5331d4..f723e02 100644 --- a/src/knock_mapi/types/commit_commit_all_params.py +++ b/src/knock_mapi/types/commit_commit_all_params.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import List, Union +from typing_extensions import Literal, Required, TypedDict __all__ = ["CommitCommitAllParams"] @@ -13,3 +14,19 @@ class CommitCommitAllParams(TypedDict, total=False): commit_message: str """An optional message to include in a commit.""" + + resource_id: str + """Filter changes to commit by resource identifier. + + Must be used together with resource_type. + """ + + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + """Filter changes to commit by resource type(s). + + Accepts a single type or array of types. Can be combined with resource_id to + filter for specific resources. + """ diff --git a/src/knock_mapi/types/commit_list_params.py b/src/knock_mapi/types/commit_list_params.py index dd785dc..a9f2bce 100644 --- a/src/knock_mapi/types/commit_list_params.py +++ b/src/knock_mapi/types/commit_list_params.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import List, Union from typing_extensions import Literal, Required, TypedDict __all__ = ["CommitListParams"] @@ -34,5 +35,12 @@ class CommitListParams(TypedDict, total=False): namespace, separated by a `/`. For example, `en/courses` or `en`. """ - resource_type: Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"] - """Filter commits by resource type. Must be used together with resource_id.""" + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + """Filter commits by resource type(s). + + Accepts a single type or array of types. Can be combined with resource_id to + filter for specific resources. + """ diff --git a/src/knock_mapi/types/commit_promote_all_params.py b/src/knock_mapi/types/commit_promote_all_params.py index 22b7fb2..1309013 100644 --- a/src/knock_mapi/types/commit_promote_all_params.py +++ b/src/knock_mapi/types/commit_promote_all_params.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing_extensions import Required, TypedDict +from typing import List, Union +from typing_extensions import Literal, Required, TypedDict __all__ = ["CommitPromoteAllParams"] @@ -19,3 +20,19 @@ class CommitPromoteAllParams(TypedDict, total=False): Note: This must be a non-development environment. """ + + resource_id: str + """Filter commits to promote by resource identifier. + + Must be used together with resource_type. + """ + + resource_type: Union[ + Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], + List[Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]], + ] + """Filter commits to promote by resource type(s). + + Accepts a single type or array of types. Can be combined with resource_id to + filter for specific resources. + """ diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 61b8252..1608b49 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -127,6 +127,8 @@ def test_method_commit_all_with_all_params(self, client: KnockMgmt) -> None: commit = client.commits.commit_all( environment="development", commit_message="commit_message", + resource_id="resource_id", + resource_type="audience", ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) @@ -164,6 +166,16 @@ def test_method_promote_all(self, client: KnockMgmt) -> None: ) assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_promote_all_with_all_params(self, client: KnockMgmt) -> None: + commit = client.commits.promote_all( + to_environment="to_environment", + resource_id="resource_id", + resource_type="audience", + ) + assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_promote_all(self, client: KnockMgmt) -> None: @@ -342,6 +354,8 @@ async def test_method_commit_all_with_all_params(self, async_client: AsyncKnockM commit = await async_client.commits.commit_all( environment="development", commit_message="commit_message", + resource_id="resource_id", + resource_type="audience", ) assert_matches_type(CommitCommitAllResponse, commit, path=["response"]) @@ -379,6 +393,16 @@ async def test_method_promote_all(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_promote_all_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + commit = await async_client.commits.promote_all( + to_environment="to_environment", + resource_id="resource_id", + resource_type="audience", + ) + assert_matches_type(CommitPromoteAllResponse, commit, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_promote_all(self, async_client: AsyncKnockMgmt) -> None: From 1ec851f416e69862f0eb5e98d3eec7bda2dcb4c5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 17:04:36 +0000 Subject: [PATCH 073/101] feat(api): api update --- .stats.yml | 4 +- api.md | 1 - src/knock_mapi/types/__init__.py | 2 - src/knock_mapi/types/workflow_channel_step.py | 78 ---- .../types/workflow_channel_step_param.py | 90 ----- src/knock_mapi/types/workflow_step.py | 336 +++++++++++++++++- src/knock_mapi/types/workflow_step_param.py | 335 ++++++++++++++++- tests/api_resources/test_workflows.py | 48 +-- 8 files changed, 665 insertions(+), 229 deletions(-) delete mode 100644 src/knock_mapi/types/workflow_channel_step.py delete mode 100644 src/knock_mapi/types/workflow_channel_step_param.py diff --git a/.stats.yml b/.stats.yml index c340bbc..3e1a8b6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-edf7c2dadb8d5434be9dea2bb70f6d1a52f8aa9754258014ba9716f5a103c65b.yml -openapi_spec_hash: 763acd11ec0b5dbf2301a1cbcf7aac47 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml +openapi_spec_hash: 3773026857f48ace6938850a61023805 config_hash: f9e83854b42d2264516f449568348afa diff --git a/api.md b/api.md index 440f5a6..a91979e 100644 --- a/api.md +++ b/api.md @@ -104,7 +104,6 @@ from knock_mapi.types import ( Workflow, WorkflowBatchStep, WorkflowBranchStep, - WorkflowChannelStep, WorkflowDelayStep, WorkflowFetchStep, WorkflowStep, diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 5f274b8..cf9da87 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -69,7 +69,6 @@ from .guide_validate_params import GuideValidateParams as GuideValidateParams from .partial_upsert_params import PartialUpsertParams as PartialUpsertParams from .push_channel_settings import PushChannelSettings as PushChannelSettings -from .workflow_channel_step import WorkflowChannelStep as WorkflowChannelStep from .workflow_run_response import WorkflowRunResponse as WorkflowRunResponse from .email_channel_settings import EmailChannelSettings as EmailChannelSettings from .request_template_param import RequestTemplateParam as RequestTemplateParam @@ -117,7 +116,6 @@ from .translation_retrieve_params import TranslationRetrieveParams as TranslationRetrieveParams from .translation_upsert_response import TranslationUpsertResponse as TranslationUpsertResponse from .translation_validate_params import TranslationValidateParams as TranslationValidateParams -from .workflow_channel_step_param import WorkflowChannelStepParam as WorkflowChannelStepParam from .email_channel_settings_param import EmailChannelSettingsParam as EmailChannelSettingsParam from .email_layout_retrieve_params import EmailLayoutRetrieveParams as EmailLayoutRetrieveParams from .email_layout_upsert_response import EmailLayoutUpsertResponse as EmailLayoutUpsertResponse diff --git a/src/knock_mapi/types/workflow_channel_step.py b/src/knock_mapi/types/workflow_channel_step.py deleted file mode 100644 index 2f2e93a..0000000 --- a/src/knock_mapi/types/workflow_channel_step.py +++ /dev/null @@ -1,78 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from .._models import BaseModel -from .send_window import SendWindow -from .sms_template import SMSTemplate -from .chat_template import ChatTemplate -from .push_template import PushTemplate -from .email_template import EmailTemplate -from .condition_group import ConditionGroup -from .webhook_template import WebhookTemplate -from .in_app_feed_template import InAppFeedTemplate -from .sms_channel_settings import SMSChannelSettings -from .chat_channel_settings import ChatChannelSettings -from .push_channel_settings import PushChannelSettings -from .email_channel_settings import EmailChannelSettings -from .in_app_feed_channel_settings import InAppFeedChannelSettings - -__all__ = ["WorkflowChannelStep", "Template", "ChannelOverrides"] - -Template: TypeAlias = Union[EmailTemplate, InAppFeedTemplate, SMSTemplate, PushTemplate, ChatTemplate, WebhookTemplate] - -ChannelOverrides: TypeAlias = Union[ - EmailChannelSettings, InAppFeedChannelSettings, SMSChannelSettings, PushChannelSettings, ChatChannelSettings, None -] - - -class WorkflowChannelStep(BaseModel): - name: str - """A name for the workflow step.""" - - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Template - """The message template for the channel step. - - The shape of the template depends on the type of the channel you'll be sending - to. See below for definitions of each channel type template: email, in-app, SMS, - push, chat, and webhook. - """ - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[ChannelOverrides] = None - """A map of channel overrides for the channel step.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ diff --git a/src/knock_mapi/types/workflow_channel_step_param.py b/src/knock_mapi/types/workflow_channel_step_param.py deleted file mode 100644 index 41b81c0..0000000 --- a/src/knock_mapi/types/workflow_channel_step_param.py +++ /dev/null @@ -1,90 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .send_window_param import SendWindowParam -from .sms_template_param import SMSTemplateParam -from .chat_template_param import ChatTemplateParam -from .push_template_param import PushTemplateParam -from .email_template_param import EmailTemplateParam -from .condition_group_param import ConditionGroupParam -from .webhook_template_param import WebhookTemplateParam -from .in_app_feed_template_param import InAppFeedTemplateParam -from .sms_channel_settings_param import SMSChannelSettingsParam -from .chat_channel_settings_param import ChatChannelSettingsParam -from .push_channel_settings_param import PushChannelSettingsParam -from .email_channel_settings_param import EmailChannelSettingsParam -from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam - -__all__ = ["WorkflowChannelStepParam", "Template", "ChannelOverrides"] - -Template: TypeAlias = Union[ - EmailTemplateParam, - InAppFeedTemplateParam, - SMSTemplateParam, - PushTemplateParam, - ChatTemplateParam, - WebhookTemplateParam, -] - -ChannelOverrides: TypeAlias = Union[ - EmailChannelSettingsParam, - InAppFeedChannelSettingsParam, - SMSChannelSettingsParam, - PushChannelSettingsParam, - ChatChannelSettingsParam, -] - - -class WorkflowChannelStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[Template] - """The message template for the channel step. - - The shape of the template depends on the type of the channel you'll be sending - to. See below for definitions of each channel type template: email, in-app, SMS, - push, chat, and webhook. - """ - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[ChannelOverrides] - """A map of channel overrides for the channel step.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py index e5b8a66..9bbae1c 100644 --- a/src/knock_mapi/types/workflow_step.py +++ b/src/knock_mapi/types/workflow_step.py @@ -2,24 +2,343 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Union -from typing_extensions import TypeAlias, TypeAliasType +from typing import TYPE_CHECKING, List, Union, Optional +from typing_extensions import Literal, TypeAlias, TypeAliasType from .._compat import PYDANTIC_V1 +from .._models import BaseModel +from .send_window import SendWindow +from .sms_template import SMSTemplate +from .chat_template import ChatTemplate +from .push_template import PushTemplate +from .email_template import EmailTemplate +from .condition_group import ConditionGroup +from .webhook_template import WebhookTemplate from .workflow_batch_step import WorkflowBatchStep from .workflow_delay_step import WorkflowDelayStep from .workflow_fetch_step import WorkflowFetchStep -from .workflow_channel_step import WorkflowChannelStep +from .in_app_feed_template import InAppFeedTemplate +from .sms_channel_settings import SMSChannelSettings +from .chat_channel_settings import ChatChannelSettings +from .push_channel_settings import PushChannelSettings +from .email_channel_settings import EmailChannelSettings from .workflow_throttle_step import WorkflowThrottleStep +from .in_app_feed_channel_settings import InAppFeedChannelSettings from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep -__all__ = ["WorkflowStep"] +__all__ = [ + "WorkflowStep", + "WorkflowWebhookStep", + "WorkflowInAppFeedStep", + "WorkflowChatStep", + "WorkflowSMSStep", + "WorkflowPushStep", + "WorkflowEmailStep", +] + + +class WorkflowWebhookStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: WebhookTemplate + """A webhook template. + + By default, a webhook step will use the request settings you configured in your + webhook channel. You can override this as you see fit on a per-step basis. + """ + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowInAppFeedStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: InAppFeedTemplate + """An in-app feed template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[InAppFeedChannelSettings] = None + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowChatStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: ChatTemplate + """A chat template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[ChatChannelSettings] = None + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowSMSStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: SMSTemplate + """An SMS template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[SMSChannelSettings] = None + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowPushStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: PushTemplate + """A push notification template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[PushChannelSettings] = None + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowEmailStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: EmailTemplate + """An email message template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[EmailChannelSettings] = None + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ + if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStep = TypeAliasType( "WorkflowStep", Union[ - WorkflowChannelStep, + WorkflowWebhookStep, + WorkflowInAppFeedStep, + WorkflowChatStep, + WorkflowSMSStep, + WorkflowPushStep, + WorkflowEmailStep, WorkflowDelayStep, WorkflowBatchStep, WorkflowFetchStep, @@ -30,7 +349,12 @@ ) else: WorkflowStep: TypeAlias = Union[ - WorkflowChannelStep, + WorkflowWebhookStep, + WorkflowInAppFeedStep, + WorkflowChatStep, + WorkflowSMSStep, + WorkflowPushStep, + WorkflowEmailStep, WorkflowDelayStep, WorkflowBatchStep, WorkflowFetchStep, diff --git a/src/knock_mapi/types/workflow_step_param.py b/src/knock_mapi/types/workflow_step_param.py index 88a518f..caef4d2 100644 --- a/src/knock_mapi/types/workflow_step_param.py +++ b/src/knock_mapi/types/workflow_step_param.py @@ -2,24 +2,342 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Union -from typing_extensions import TypeAlias, TypeAliasType +from typing import TYPE_CHECKING, Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict, TypeAliasType from .._compat import PYDANTIC_V1 +from .send_window_param import SendWindowParam +from .sms_template_param import SMSTemplateParam +from .chat_template_param import ChatTemplateParam +from .push_template_param import PushTemplateParam +from .email_template_param import EmailTemplateParam +from .condition_group_param import ConditionGroupParam +from .webhook_template_param import WebhookTemplateParam from .workflow_batch_step_param import WorkflowBatchStepParam from .workflow_delay_step_param import WorkflowDelayStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam -from .workflow_channel_step_param import WorkflowChannelStepParam +from .in_app_feed_template_param import InAppFeedTemplateParam +from .sms_channel_settings_param import SMSChannelSettingsParam +from .chat_channel_settings_param import ChatChannelSettingsParam +from .push_channel_settings_param import PushChannelSettingsParam +from .email_channel_settings_param import EmailChannelSettingsParam from .workflow_throttle_step_param import WorkflowThrottleStepParam +from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam -__all__ = ["WorkflowStepParam"] +__all__ = [ + "WorkflowStepParam", + "WorkflowWebhookStep", + "WorkflowInAppFeedStep", + "WorkflowChatStep", + "WorkflowSMSStep", + "WorkflowPushStep", + "WorkflowEmailStep", +] + + +class WorkflowWebhookStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[WebhookTemplateParam] + """A webhook template. + + By default, a webhook step will use the request settings you configured in your + webhook channel. You can override this as you see fit on a per-step basis. + """ + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowInAppFeedStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[InAppFeedTemplateParam] + """An in-app feed template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[InAppFeedChannelSettingsParam] + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowChatStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[ChatTemplateParam] + """A chat template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[ChatChannelSettingsParam] + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowSMSStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[SMSTemplateParam] + """An SMS template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[SMSChannelSettingsParam] + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowPushStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[PushTemplateParam] + """A push notification template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[PushChannelSettingsParam] + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + + +class WorkflowEmailStep(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[EmailTemplateParam] + """An email message template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[EmailChannelSettingsParam] + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ + if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStepParam = TypeAliasType( "WorkflowStepParam", Union[ - WorkflowChannelStepParam, + WorkflowWebhookStep, + WorkflowInAppFeedStep, + WorkflowChatStep, + WorkflowSMSStep, + WorkflowPushStep, + WorkflowEmailStep, WorkflowDelayStepParam, WorkflowBatchStepParam, WorkflowFetchStepParam, @@ -30,7 +348,12 @@ ) else: WorkflowStepParam: TypeAlias = Union[ - WorkflowChannelStepParam, + WorkflowWebhookStep, + WorkflowInAppFeedStep, + WorkflowChatStep, + WorkflowSMSStep, + WorkflowPushStep, + WorkflowEmailStep, WorkflowDelayStepParam, WorkflowBatchStepParam, WorkflowFetchStepParam, diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 8db495b..e34329f 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -291,17 +291,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "type": "channel", "channel_group_key": None, "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, + "channel_overrides": {"link_tracking": True}, "conditions": { "all": [ { @@ -461,17 +451,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "type": "channel", "channel_group_key": None, "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, + "channel_overrides": {"link_tracking": True}, "conditions": { "all": [ { @@ -855,17 +835,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "type": "channel", "channel_group_key": None, "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, + "channel_overrides": {"link_tracking": True}, "conditions": { "all": [ { @@ -1025,17 +995,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "type": "channel", "channel_group_key": None, "channel_key": "in-app-feed", - "channel_overrides": { - "bcc_address": None, - "cc_address": None, - "from_address": "hello@example.com", - "from_name": "John Doe", - "json_overrides": '{"some_override": true}', - "link_tracking": True, - "open_tracking": True, - "reply_to_address": None, - "to_address": "hello@example.com", - }, + "channel_overrides": {"link_tracking": True}, "conditions": { "all": [ { From 7ac609f7f98b3a5b5fc98ca5845faf2f52351594 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:56:07 +0000 Subject: [PATCH 074/101] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 3e1a8b6..6e3f361 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml openapi_spec_hash: 3773026857f48ace6938850a61023805 -config_hash: f9e83854b42d2264516f449568348afa +config_hash: 6408249aba722fc16278d7efceb8d2f2 From 3b657ada4768db559b1ee96fc69b1f7f34c736c1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:42:34 +0000 Subject: [PATCH 075/101] feat(api): api update --- .stats.yml | 4 +- src/knock_mapi/types/workflow_batch_step.py | 18 +++---- .../types/workflow_batch_step_param.py | 18 +++---- src/knock_mapi/types/workflow_branch_step.py | 16 +++--- .../types/workflow_branch_step_param.py | 16 +++--- src/knock_mapi/types/workflow_delay_step.py | 24 ++++----- .../types/workflow_delay_step_param.py | 24 ++++----- src/knock_mapi/types/workflow_fetch_step.py | 8 +-- .../types/workflow_fetch_step_param.py | 8 +-- src/knock_mapi/types/workflow_step.py | 54 ++++++++++++------- src/knock_mapi/types/workflow_step_param.py | 54 ++++++++++++------- .../types/workflow_throttle_step.py | 6 +-- .../types/workflow_throttle_step_param.py | 6 +-- .../types/workflow_trigger_workflow_step.py | 6 +-- .../workflow_trigger_workflow_step_param.py | 8 +-- tests/api_resources/test_workflows.py | 28 +++------- 16 files changed, 161 insertions(+), 137 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6e3f361..6fe6ee7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml -openapi_spec_hash: 3773026857f48ace6938850a61023805 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-11b93111b3fcec2e7fdb30e113b0deb03cea8b42c80e03be9a50ebad0f81663d.yml +openapi_spec_hash: c1732237aba39851ff1c185b8fe8458f config_hash: 6408249aba722fc16278d7efceb8d2f2 diff --git a/src/knock_mapi/types/workflow_batch_step.py b/src/knock_mapi/types/workflow_batch_step.py index edf6d17..ee09ea9 100644 --- a/src/knock_mapi/types/workflow_batch_step.py +++ b/src/knock_mapi/types/workflow_batch_step.py @@ -55,15 +55,6 @@ class Settings(BaseModel): class WorkflowBatchStep(BaseModel): - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -72,3 +63,12 @@ class WorkflowBatchStep(BaseModel): type: Literal["batch"] """The type of the workflow step.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_batch_step_param.py b/src/knock_mapi/types/workflow_batch_step_param.py index 5c56ca3..bea4c5b 100644 --- a/src/knock_mapi/types/workflow_batch_step_param.py +++ b/src/knock_mapi/types/workflow_batch_step_param.py @@ -56,15 +56,6 @@ class Settings(TypedDict, total=False): class WorkflowBatchStepParam(TypedDict, total=False): - description: Required[Optional[str]] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -73,3 +64,12 @@ class WorkflowBatchStepParam(TypedDict, total=False): type: Required[Literal["batch"]] """The type of the workflow step.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_branch_step.py b/src/knock_mapi/types/workflow_branch_step.py index 273d762..f6f269c 100644 --- a/src/knock_mapi/types/workflow_branch_step.py +++ b/src/knock_mapi/types/workflow_branch_step.py @@ -29,20 +29,20 @@ class WorkflowBranchStep(BaseModel): branches: List[Branch] """A list of workflow branches to be evaluated.""" - description: str + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Literal["branch"] + """The type of step.""" + + description: Optional[str] = None """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: str + name: Optional[str] = None """A name for the workflow step.""" - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Literal["branch"] - """The type of step.""" - from .workflow_step import WorkflowStep diff --git a/src/knock_mapi/types/workflow_branch_step_param.py b/src/knock_mapi/types/workflow_branch_step_param.py index 85e2505..aab34f8 100644 --- a/src/knock_mapi/types/workflow_branch_step_param.py +++ b/src/knock_mapi/types/workflow_branch_step_param.py @@ -28,20 +28,20 @@ class WorkflowBranchStepParam(TypedDict, total=False): branches: Required[Iterable[Branch]] """A list of workflow branches to be evaluated.""" - description: Required[str] + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Required[Literal["branch"]] + """The type of step.""" + + description: str """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: Required[str] + name: Optional[str] """A name for the workflow step.""" - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Required[Literal["branch"]] - """The type of step.""" - from .workflow_step_param import WorkflowStepParam diff --git a/src/knock_mapi/types/workflow_delay_step.py b/src/knock_mapi/types/workflow_delay_step.py index 3f3fe5a..e14ac7e 100644 --- a/src/knock_mapi/types/workflow_delay_step.py +++ b/src/knock_mapi/types/workflow_delay_step.py @@ -22,18 +22,6 @@ class Settings(BaseModel): class WorkflowDelayStep(BaseModel): - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,3 +34,15 @@ class WorkflowDelayStep(BaseModel): type: Literal["delay"] """The type of the workflow step.""" + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_delay_step_param.py b/src/knock_mapi/types/workflow_delay_step_param.py index 14a6dd3..ffe6510 100644 --- a/src/knock_mapi/types/workflow_delay_step_param.py +++ b/src/knock_mapi/types/workflow_delay_step_param.py @@ -23,18 +23,6 @@ class Settings(TypedDict, total=False): class WorkflowDelayStepParam(TypedDict, total=False): - conditions: Required[Optional[ConditionGroupParam]] - """A group of conditions to be evaluated.""" - - description: Required[Optional[str]] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -47,3 +35,15 @@ class WorkflowDelayStepParam(TypedDict, total=False): type: Required[Literal["delay"]] """The type of the workflow step.""" + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_fetch_step.py b/src/knock_mapi/types/workflow_fetch_step.py index 03e5a5a..a7792b3 100644 --- a/src/knock_mapi/types/workflow_fetch_step.py +++ b/src/knock_mapi/types/workflow_fetch_step.py @@ -11,16 +11,13 @@ class WorkflowFetchStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" settings: RequestTemplate """A request template for a fetch function step.""" - type: Literal["fetch"] + type: Literal["http_fetch"] """The type of the workflow step.""" conditions: Optional[ConditionGroup] = None @@ -31,3 +28,6 @@ class WorkflowFetchStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_fetch_step_param.py b/src/knock_mapi/types/workflow_fetch_step_param.py index da2e56f..8dd73ec 100644 --- a/src/knock_mapi/types/workflow_fetch_step_param.py +++ b/src/knock_mapi/types/workflow_fetch_step_param.py @@ -12,16 +12,13 @@ class WorkflowFetchStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" settings: Required[RequestTemplateParam] """A request template for a fetch function step.""" - type: Required[Literal["fetch"]] + type: Required[Literal["http_fetch"]] """The type of the workflow step.""" conditions: Optional[ConditionGroupParam] @@ -32,3 +29,6 @@ class WorkflowFetchStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py index 9bbae1c..6f8efb3 100644 --- a/src/knock_mapi/types/workflow_step.py +++ b/src/knock_mapi/types/workflow_step.py @@ -38,9 +38,6 @@ class WorkflowWebhookStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -68,6 +65,9 @@ class WorkflowWebhookStep(BaseModel): both. """ + channel_type: Optional[Literal["http"]] = None + """The type of the channel step. Always `http` for webhook steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -77,6 +77,9 @@ class WorkflowWebhookStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. @@ -85,9 +88,6 @@ class WorkflowWebhookStep(BaseModel): class WorkflowInAppFeedStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -117,6 +117,9 @@ class WorkflowInAppFeedStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["in_app_feed"]] = None + """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -126,6 +129,9 @@ class WorkflowInAppFeedStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. @@ -134,9 +140,6 @@ class WorkflowInAppFeedStep(BaseModel): class WorkflowChatStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -166,6 +169,9 @@ class WorkflowChatStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["chat"]] = None + """The type of the channel step. Always `chat` for chat steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -175,6 +181,9 @@ class WorkflowChatStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. @@ -183,9 +192,6 @@ class WorkflowChatStep(BaseModel): class WorkflowSMSStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -215,6 +221,9 @@ class WorkflowSMSStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["sms"]] = None + """The type of the channel step. Always `sms` for SMS steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -224,6 +233,9 @@ class WorkflowSMSStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. @@ -232,9 +244,6 @@ class WorkflowSMSStep(BaseModel): class WorkflowPushStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -264,6 +273,9 @@ class WorkflowPushStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["push"]] = None + """The type of the channel step. Always `push` for push steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -273,6 +285,9 @@ class WorkflowPushStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. @@ -281,9 +296,6 @@ class WorkflowPushStep(BaseModel): class WorkflowEmailStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -313,6 +325,9 @@ class WorkflowEmailStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["email"]] = None + """The type of the channel step. Always `email` for email steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -322,6 +337,9 @@ class WorkflowEmailStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_step_param.py b/src/knock_mapi/types/workflow_step_param.py index caef4d2..ca4417f 100644 --- a/src/knock_mapi/types/workflow_step_param.py +++ b/src/knock_mapi/types/workflow_step_param.py @@ -37,9 +37,6 @@ class WorkflowWebhookStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -67,6 +64,9 @@ class WorkflowWebhookStep(TypedDict, total=False): both. """ + channel_type: Literal["http"] + """The type of the channel step. Always `http` for webhook steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -76,6 +76,9 @@ class WorkflowWebhookStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -84,9 +87,6 @@ class WorkflowWebhookStep(TypedDict, total=False): class WorkflowInAppFeedStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -116,6 +116,9 @@ class WorkflowInAppFeedStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["in_app_feed"] + """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -125,6 +128,9 @@ class WorkflowInAppFeedStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -133,9 +139,6 @@ class WorkflowInAppFeedStep(TypedDict, total=False): class WorkflowChatStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -165,6 +168,9 @@ class WorkflowChatStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["chat"] + """The type of the channel step. Always `chat` for chat steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -174,6 +180,9 @@ class WorkflowChatStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -182,9 +191,6 @@ class WorkflowChatStep(TypedDict, total=False): class WorkflowSMSStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -214,6 +220,9 @@ class WorkflowSMSStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["sms"] + """The type of the channel step. Always `sms` for SMS steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -223,6 +232,9 @@ class WorkflowSMSStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -231,9 +243,6 @@ class WorkflowSMSStep(TypedDict, total=False): class WorkflowPushStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -263,6 +272,9 @@ class WorkflowPushStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["push"] + """The type of the channel step. Always `push` for push steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -272,6 +284,9 @@ class WorkflowPushStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -280,9 +295,6 @@ class WorkflowPushStep(TypedDict, total=False): class WorkflowEmailStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -312,6 +324,9 @@ class WorkflowEmailStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["email"] + """The type of the channel step. Always `email` for email steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -321,6 +336,9 @@ class WorkflowEmailStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_throttle_step.py b/src/knock_mapi/types/workflow_throttle_step.py index 74f7e98..6f1d4fc 100644 --- a/src/knock_mapi/types/workflow_throttle_step.py +++ b/src/knock_mapi/types/workflow_throttle_step.py @@ -32,9 +32,6 @@ class Settings(BaseModel): class WorkflowThrottleStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -52,3 +49,6 @@ class WorkflowThrottleStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_throttle_step_param.py b/src/knock_mapi/types/workflow_throttle_step_param.py index 9b83b4a..cb9dac7 100644 --- a/src/knock_mapi/types/workflow_throttle_step_param.py +++ b/src/knock_mapi/types/workflow_throttle_step_param.py @@ -33,9 +33,6 @@ class Settings(TypedDict, total=False): class WorkflowThrottleStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -53,3 +50,6 @@ class WorkflowThrottleStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step.py b/src/knock_mapi/types/workflow_trigger_workflow_step.py index 96e6e88..f14d346 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step.py @@ -30,9 +30,6 @@ class Settings(BaseModel): class WorkflowTriggerWorkflowStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -47,3 +44,6 @@ class WorkflowTriggerWorkflowStep(BaseModel): description: Optional[str] = None """A description for the workflow step.""" + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py index 1469d0d..6f78254 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py @@ -31,9 +31,6 @@ class Settings(TypedDict, total=False): class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,5 +43,8 @@ class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" - description: str + description: Optional[str] """A description for the workflow step.""" + + name: Optional[str] + """A name for the workflow step.""" diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index e34329f..6a7954f 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -256,7 +256,6 @@ def test_method_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -276,7 +275,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -292,6 +290,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -302,6 +301,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -346,7 +346,6 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -370,7 +369,6 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -397,7 +395,6 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -416,7 +413,6 @@ def test_method_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -436,7 +432,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -452,6 +447,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -462,6 +458,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -503,7 +500,6 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -527,7 +523,6 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -554,7 +549,6 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -800,7 +794,6 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -820,7 +813,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -836,6 +828,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -846,6 +839,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -890,7 +884,6 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -914,7 +907,6 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -941,7 +933,6 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -960,7 +951,6 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -980,7 +970,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -996,6 +985,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -1006,6 +996,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -1047,7 +1038,6 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1071,7 +1061,6 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1098,7 +1087,6 @@ async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", From 6b9a3630f2860dd489a73ef9b3a205eeba54038b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 01:07:24 +0000 Subject: [PATCH 076/101] feat(api): add new guide methods --- .stats.yml | 8 +- api.md | 8 + src/knock_mapi/resources/guides.py | 79 +++++ src/knock_mapi/types/__init__.py | 13 + src/knock_mapi/types/guide.py | 14 +- .../types/guide_activation_url_pattern.py | 15 + .../guide_activation_url_pattern_param.py | 15 + .../types/guide_archive_response.py | 10 + src/knock_mapi/types/guide_upsert_params.py | 15 +- src/knock_mapi/types/guide_validate_params.py | 15 +- src/knock_mapi/types/workflow_batch_step.py | 18 +- .../types/workflow_batch_step_param.py | 18 +- src/knock_mapi/types/workflow_branch_step.py | 16 +- .../types/workflow_branch_step_param.py | 16 +- src/knock_mapi/types/workflow_chat_step.py | 61 ++++ .../types/workflow_chat_step_param.py | 62 ++++ src/knock_mapi/types/workflow_delay_step.py | 24 +- .../types/workflow_delay_step_param.py | 24 +- src/knock_mapi/types/workflow_email_step.py | 61 ++++ .../types/workflow_email_step_param.py | 62 ++++ src/knock_mapi/types/workflow_fetch_step.py | 8 +- .../types/workflow_fetch_step_param.py | 8 +- src/knock_mapi/types/workflow_push_step.py | 61 ++++ .../types/workflow_push_step_param.py | 62 ++++ src/knock_mapi/types/workflow_sms_step.py | 61 ++++ .../types/workflow_sms_step_param.py | 62 ++++ src/knock_mapi/types/workflow_step.py | 289 +--------------- src/knock_mapi/types/workflow_step_param.py | 309 +----------------- .../types/workflow_throttle_step.py | 6 +- .../types/workflow_throttle_step_param.py | 6 +- .../types/workflow_trigger_workflow_step.py | 6 +- .../workflow_trigger_workflow_step_param.py | 8 +- src/knock_mapi/types/workflow_webhook_step.py | 58 ++++ .../types/workflow_webhook_step_param.py | 59 ++++ tests/api_resources/test_guides.py | 85 +++++ tests/api_resources/test_workflows.py | 28 +- 36 files changed, 974 insertions(+), 696 deletions(-) create mode 100644 src/knock_mapi/types/guide_activation_url_pattern.py create mode 100644 src/knock_mapi/types/guide_activation_url_pattern_param.py create mode 100644 src/knock_mapi/types/guide_archive_response.py create mode 100644 src/knock_mapi/types/workflow_chat_step.py create mode 100644 src/knock_mapi/types/workflow_chat_step_param.py create mode 100644 src/knock_mapi/types/workflow_email_step.py create mode 100644 src/knock_mapi/types/workflow_email_step_param.py create mode 100644 src/knock_mapi/types/workflow_push_step.py create mode 100644 src/knock_mapi/types/workflow_push_step_param.py create mode 100644 src/knock_mapi/types/workflow_sms_step.py create mode 100644 src/knock_mapi/types/workflow_sms_step_param.py create mode 100644 src/knock_mapi/types/workflow_webhook_step.py create mode 100644 src/knock_mapi/types/workflow_webhook_step_param.py diff --git a/.stats.yml b/.stats.yml index 6fe6ee7..a89ee0d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 40 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-11b93111b3fcec2e7fdb30e113b0deb03cea8b42c80e03be9a50ebad0f81663d.yml -openapi_spec_hash: c1732237aba39851ff1c185b8fe8458f -config_hash: 6408249aba722fc16278d7efceb8d2f2 +configured_endpoints: 41 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml +openapi_spec_hash: 3773026857f48ace6938850a61023805 +config_hash: d70caf0fe85f6af45c65894eaf6ca490 diff --git a/api.md b/api.md index a91979e..79dd8da 100644 --- a/api.md +++ b/api.md @@ -104,11 +104,16 @@ from knock_mapi.types import ( Workflow, WorkflowBatchStep, WorkflowBranchStep, + WorkflowChatStep, WorkflowDelayStep, + WorkflowEmailStep, WorkflowFetchStep, + WorkflowPushStep, + WorkflowSMSStep, WorkflowStep, WorkflowThrottleStep, WorkflowTriggerWorkflowStep, + WorkflowWebhookStep, WorkflowRetrieveResponse, WorkflowActivateResponse, WorkflowRunResponse, @@ -246,8 +251,10 @@ Types: ```python from knock_mapi.types import ( Guide, + GuideActivationURLPattern, GuideStep, GuideActivateResponse, + GuideArchiveResponse, GuideUpsertResponse, GuideValidateResponse, ) @@ -258,5 +265,6 @@ Methods: - client.guides.retrieve(guide_key, \*\*params) -> Guide - client.guides.list(\*\*params) -> SyncEntriesCursor[Guide] - client.guides.activate(guide_key, \*\*params) -> GuideActivateResponse +- client.guides.archive(guide_key) -> GuideArchiveResponse - client.guides.upsert(guide_key, \*\*params) -> GuideUpsertResponse - client.guides.validate(guide_key, \*\*params) -> GuideValidateResponse diff --git a/src/knock_mapi/resources/guides.py b/src/knock_mapi/resources/guides.py index 61b868d..b4cfc5e 100644 --- a/src/knock_mapi/resources/guides.py +++ b/src/knock_mapi/resources/guides.py @@ -29,6 +29,7 @@ from ..types.guide import Guide from .._base_client import AsyncPaginator, make_request_options from ..types.guide_upsert_response import GuideUpsertResponse +from ..types.guide_archive_response import GuideArchiveResponse from ..types.guide_activate_response import GuideActivateResponse from ..types.guide_validate_response import GuideValidateResponse @@ -290,6 +291,39 @@ def activate( cast_to=GuideActivateResponse, ) + def archive( + self, + guide_key: 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, + ) -> GuideArchiveResponse: + """ + Archives a given guide across all environments. + + 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return self._delete( + f"/v1/guides/{guide_key}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GuideArchiveResponse, + ) + def upsert( self, guide_key: str, @@ -657,6 +691,39 @@ async def activate( cast_to=GuideActivateResponse, ) + async def archive( + self, + guide_key: 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, + ) -> GuideArchiveResponse: + """ + Archives a given guide across all environments. + + 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 guide_key: + raise ValueError(f"Expected a non-empty value for `guide_key` but received {guide_key!r}") + return await self._delete( + f"/v1/guides/{guide_key}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=GuideArchiveResponse, + ) + async def upsert( self, guide_key: str, @@ -782,6 +849,9 @@ def __init__(self, guides: GuidesResource) -> None: self.activate = to_raw_response_wrapper( guides.activate, ) + self.archive = to_raw_response_wrapper( + guides.archive, + ) self.upsert = to_raw_response_wrapper( guides.upsert, ) @@ -803,6 +873,9 @@ def __init__(self, guides: AsyncGuidesResource) -> None: self.activate = async_to_raw_response_wrapper( guides.activate, ) + self.archive = async_to_raw_response_wrapper( + guides.archive, + ) self.upsert = async_to_raw_response_wrapper( guides.upsert, ) @@ -824,6 +897,9 @@ def __init__(self, guides: GuidesResource) -> None: self.activate = to_streamed_response_wrapper( guides.activate, ) + self.archive = to_streamed_response_wrapper( + guides.archive, + ) self.upsert = to_streamed_response_wrapper( guides.upsert, ) @@ -845,6 +921,9 @@ def __init__(self, guides: AsyncGuidesResource) -> None: self.activate = async_to_streamed_response_wrapper( guides.activate, ) + self.archive = async_to_streamed_response_wrapper( + guides.archive, + ) self.upsert = async_to_streamed_response_wrapper( guides.upsert, ) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index cf9da87..0bfa94d 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -40,9 +40,12 @@ from .webhook_template import WebhookTemplate as WebhookTemplate from .guide_list_params import GuideListParams as GuideListParams from .send_window_param import SendWindowParam as SendWindowParam +from .workflow_sms_step import WorkflowSMSStep as WorkflowSMSStep from .channel_group_rule import ChannelGroupRule as ChannelGroupRule from .commit_list_params import CommitListParams as CommitListParams from .sms_template_param import SMSTemplateParam as SMSTemplateParam +from .workflow_chat_step import WorkflowChatStep as WorkflowChatStep +from .workflow_push_step import WorkflowPushStep as WorkflowPushStep from .channel_list_params import ChannelListParams as ChannelListParams from .chat_template_param import ChatTemplateParam as ChatTemplateParam from .guide_upsert_params import GuideUpsertParams as GuideUpsertParams @@ -50,6 +53,7 @@ from .push_template_param import PushTemplateParam as PushTemplateParam from .workflow_batch_step import WorkflowBatchStep as WorkflowBatchStep from .workflow_delay_step import WorkflowDelayStep as WorkflowDelayStep +from .workflow_email_step import WorkflowEmailStep as WorkflowEmailStep from .workflow_fetch_step import WorkflowFetchStep as WorkflowFetchStep from .workflow_run_params import WorkflowRunParams as WorkflowRunParams from .workflow_step_param import WorkflowStepParam as WorkflowStepParam @@ -70,7 +74,9 @@ from .partial_upsert_params import PartialUpsertParams as PartialUpsertParams from .push_channel_settings import PushChannelSettings as PushChannelSettings from .workflow_run_response import WorkflowRunResponse as WorkflowRunResponse +from .workflow_webhook_step import WorkflowWebhookStep as WorkflowWebhookStep from .email_channel_settings import EmailChannelSettings as EmailChannelSettings +from .guide_archive_response import GuideArchiveResponse as GuideArchiveResponse from .request_template_param import RequestTemplateParam as RequestTemplateParam from .webhook_template_param import WebhookTemplateParam as WebhookTemplateParam from .workflow_throttle_step import WorkflowThrottleStep as WorkflowThrottleStep @@ -84,10 +90,13 @@ from .partial_upsert_response import PartialUpsertResponse as PartialUpsertResponse from .partial_validate_params import PartialValidateParams as PartialValidateParams from .translation_list_params import TranslationListParams as TranslationListParams +from .workflow_sms_step_param import WorkflowSMSStepParam as WorkflowSMSStepParam from .commit_commit_all_params import CommitCommitAllParams as CommitCommitAllParams from .email_layout_list_params import EmailLayoutListParams as EmailLayoutListParams from .message_type_list_params import MessageTypeListParams as MessageTypeListParams from .workflow_activate_params import WorkflowActivateParams as WorkflowActivateParams +from .workflow_chat_step_param import WorkflowChatStepParam as WorkflowChatStepParam +from .workflow_push_step_param import WorkflowPushStepParam as WorkflowPushStepParam from .workflow_retrieve_params import WorkflowRetrieveParams as WorkflowRetrieveParams from .workflow_upsert_response import WorkflowUpsertResponse as WorkflowUpsertResponse from .workflow_validate_params import WorkflowValidateParams as WorkflowValidateParams @@ -98,6 +107,7 @@ from .translation_upsert_params import TranslationUpsertParams as TranslationUpsertParams from .workflow_batch_step_param import WorkflowBatchStepParam as WorkflowBatchStepParam from .workflow_delay_step_param import WorkflowDelayStepParam as WorkflowDelayStepParam +from .workflow_email_step_param import WorkflowEmailStepParam as WorkflowEmailStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam as WorkflowFetchStepParam from .commit_commit_all_response import CommitCommitAllResponse as CommitCommitAllResponse from .email_layout_upsert_params import EmailLayoutUpsertParams as EmailLayoutUpsertParams @@ -116,10 +126,12 @@ from .translation_retrieve_params import TranslationRetrieveParams as TranslationRetrieveParams from .translation_upsert_response import TranslationUpsertResponse as TranslationUpsertResponse from .translation_validate_params import TranslationValidateParams as TranslationValidateParams +from .workflow_webhook_step_param import WorkflowWebhookStepParam as WorkflowWebhookStepParam from .email_channel_settings_param import EmailChannelSettingsParam as EmailChannelSettingsParam from .email_layout_retrieve_params import EmailLayoutRetrieveParams as EmailLayoutRetrieveParams from .email_layout_upsert_response import EmailLayoutUpsertResponse as EmailLayoutUpsertResponse from .email_layout_validate_params import EmailLayoutValidateParams as EmailLayoutValidateParams +from .guide_activation_url_pattern import GuideActivationURLPattern as GuideActivationURLPattern from .in_app_feed_channel_settings import InAppFeedChannelSettings as InAppFeedChannelSettings from .message_type_retrieve_params import MessageTypeRetrieveParams as MessageTypeRetrieveParams from .message_type_upsert_response import MessageTypeUpsertResponse as MessageTypeUpsertResponse @@ -131,6 +143,7 @@ from .email_layout_validate_response import EmailLayoutValidateResponse as EmailLayoutValidateResponse from .message_type_validate_response import MessageTypeValidateResponse as MessageTypeValidateResponse from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep as WorkflowTriggerWorkflowStep +from .guide_activation_url_pattern_param import GuideActivationURLPatternParam as GuideActivationURLPatternParam from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam as InAppFeedChannelSettingsParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam as WorkflowTriggerWorkflowStepParam diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py index 5d866ad..5d639bc 100644 --- a/src/knock_mapi/types/guide.py +++ b/src/knock_mapi/types/guide.py @@ -2,21 +2,13 @@ from typing import List, Optional from datetime import datetime -from typing_extensions import Literal from .._models import BaseModel from .guide_step import GuideStep from .condition_group import ConditionGroup +from .guide_activation_url_pattern import GuideActivationURLPattern -__all__ = ["Guide", "ActivationURLPattern"] - - -class ActivationURLPattern(BaseModel): - directive: Literal["allow", "block"] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: str - """The URL pathname pattern to match against. Must be a valid URI path.""" +__all__ = ["Guide"] class Guide(BaseModel): @@ -45,7 +37,7 @@ class Guide(BaseModel): updated_at: datetime """The timestamp of when the guide was last updated.""" - activation_url_patterns: Optional[List[ActivationURLPattern]] = None + activation_url_patterns: Optional[List[GuideActivationURLPattern]] = None """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Optional[datetime] = None diff --git a/src/knock_mapi/types/guide_activation_url_pattern.py b/src/knock_mapi/types/guide_activation_url_pattern.py new file mode 100644 index 0000000..8342450 --- /dev/null +++ b/src/knock_mapi/types/guide_activation_url_pattern.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["GuideActivationURLPattern"] + + +class GuideActivationURLPattern(BaseModel): + directive: Literal["allow", "block"] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: str + """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_activation_url_pattern_param.py b/src/knock_mapi/types/guide_activation_url_pattern_param.py new file mode 100644 index 0000000..52d4a9f --- /dev/null +++ b/src/knock_mapi/types/guide_activation_url_pattern_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["GuideActivationURLPatternParam"] + + +class GuideActivationURLPatternParam(TypedDict, total=False): + directive: Required[Literal["allow", "block"]] + """Whether to allow or block the guide at the specified pathname.""" + + pathname: Required[str] + """The URL pathname pattern to match against. Must be a valid URI path.""" diff --git a/src/knock_mapi/types/guide_archive_response.py b/src/knock_mapi/types/guide_archive_response.py new file mode 100644 index 0000000..41a14a6 --- /dev/null +++ b/src/knock_mapi/types/guide_archive_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .._models import BaseModel + +__all__ = ["GuideArchiveResponse"] + + +class GuideArchiveResponse(BaseModel): + result: str + """The result of the promote operation.""" diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index b985532..e2ec346 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -4,13 +4,14 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam +from .guide_activation_url_pattern_param import GuideActivationURLPatternParam -__all__ = ["GuideUpsertParams", "Guide", "GuideActivationURLPattern"] +__all__ = ["GuideUpsertParams", "Guide"] class GuideUpsertParams(TypedDict, total=False): @@ -30,14 +31,6 @@ class GuideUpsertParams(TypedDict, total=False): """The message to commit the resource with, only used if `commit` is `true`.""" -class GuideActivationURLPattern(TypedDict, total=False): - directive: Required[Literal["allow", "block"]] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: Required[str] - """The URL pathname pattern to match against. Must be a valid URI path.""" - - class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -48,7 +41,7 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_url_patterns: Iterable[GuideActivationURLPattern] + activation_url_patterns: Iterable[GuideActivationURLPatternParam] """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index 6a2e4aa..2c4edd4 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -4,13 +4,14 @@ from typing import Union, Iterable, Optional from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing_extensions import Required, Annotated, TypedDict from .._utils import PropertyInfo from .guide_step_param import GuideStepParam from .condition_group_param import ConditionGroupParam +from .guide_activation_url_pattern_param import GuideActivationURLPatternParam -__all__ = ["GuideValidateParams", "Guide", "GuideActivationURLPattern"] +__all__ = ["GuideValidateParams", "Guide"] class GuideValidateParams(TypedDict, total=False): @@ -21,14 +22,6 @@ class GuideValidateParams(TypedDict, total=False): """A request to create or update a guide.""" -class GuideActivationURLPattern(TypedDict, total=False): - directive: Required[Literal["allow", "block"]] - """Whether to allow or block the guide at the specified pathname.""" - - pathname: Required[str] - """The URL pathname pattern to match against. Must be a valid URI path.""" - - class Guide(TypedDict, total=False): channel_key: Required[str] """The key of the channel in which the guide exists.""" @@ -39,7 +32,7 @@ class Guide(TypedDict, total=False): steps: Required[Iterable[GuideStepParam]] """A list of guide step objects in the guide.""" - activation_url_patterns: Iterable[GuideActivationURLPattern] + activation_url_patterns: Iterable[GuideActivationURLPatternParam] """A list of activation url patterns that describe when the guide should be shown.""" archived_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] diff --git a/src/knock_mapi/types/workflow_batch_step.py b/src/knock_mapi/types/workflow_batch_step.py index ee09ea9..edf6d17 100644 --- a/src/knock_mapi/types/workflow_batch_step.py +++ b/src/knock_mapi/types/workflow_batch_step.py @@ -55,6 +55,15 @@ class Settings(BaseModel): class WorkflowBatchStep(BaseModel): + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: str + """A name for the workflow step.""" + ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -63,12 +72,3 @@ class WorkflowBatchStep(BaseModel): type: Literal["batch"] """The type of the workflow step.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_batch_step_param.py b/src/knock_mapi/types/workflow_batch_step_param.py index bea4c5b..5c56ca3 100644 --- a/src/knock_mapi/types/workflow_batch_step_param.py +++ b/src/knock_mapi/types/workflow_batch_step_param.py @@ -56,6 +56,15 @@ class Settings(TypedDict, total=False): class WorkflowBatchStepParam(TypedDict, total=False): + description: Required[Optional[str]] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Required[str] + """A name for the workflow step.""" + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -64,12 +73,3 @@ class WorkflowBatchStepParam(TypedDict, total=False): type: Required[Literal["batch"]] """The type of the workflow step.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_branch_step.py b/src/knock_mapi/types/workflow_branch_step.py index f6f269c..273d762 100644 --- a/src/knock_mapi/types/workflow_branch_step.py +++ b/src/knock_mapi/types/workflow_branch_step.py @@ -29,20 +29,20 @@ class WorkflowBranchStep(BaseModel): branches: List[Branch] """A list of workflow branches to be evaluated.""" - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Literal["branch"] - """The type of step.""" - - description: Optional[str] = None + description: str """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: Optional[str] = None + name: str """A name for the workflow step.""" + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Literal["branch"] + """The type of step.""" + from .workflow_step import WorkflowStep diff --git a/src/knock_mapi/types/workflow_branch_step_param.py b/src/knock_mapi/types/workflow_branch_step_param.py index aab34f8..85e2505 100644 --- a/src/knock_mapi/types/workflow_branch_step_param.py +++ b/src/knock_mapi/types/workflow_branch_step_param.py @@ -28,20 +28,20 @@ class WorkflowBranchStepParam(TypedDict, total=False): branches: Required[Iterable[Branch]] """A list of workflow branches to be evaluated.""" - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Required[Literal["branch"]] - """The type of step.""" - - description: str + description: Required[str] """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: Optional[str] + name: Required[str] """A name for the workflow step.""" + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Required[Literal["branch"]] + """The type of step.""" + from .workflow_step_param import WorkflowStepParam diff --git a/src/knock_mapi/types/workflow_chat_step.py b/src/knock_mapi/types/workflow_chat_step.py new file mode 100644 index 0000000..99fe775 --- /dev/null +++ b/src/knock_mapi/types/workflow_chat_step.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .chat_template import ChatTemplate +from .condition_group import ConditionGroup +from .chat_channel_settings import ChatChannelSettings + +__all__ = ["WorkflowChatStep"] + + +class WorkflowChatStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: ChatTemplate + """A chat template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[ChatChannelSettings] = None + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_chat_step_param.py b/src/knock_mapi/types/workflow_chat_step_param.py new file mode 100644 index 0000000..df5ecd9 --- /dev/null +++ b/src/knock_mapi/types/workflow_chat_step_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .chat_template_param import ChatTemplateParam +from .condition_group_param import ConditionGroupParam +from .chat_channel_settings_param import ChatChannelSettingsParam + +__all__ = ["WorkflowChatStepParam"] + + +class WorkflowChatStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[ChatTemplateParam] + """A chat template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[ChatChannelSettingsParam] + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_delay_step.py b/src/knock_mapi/types/workflow_delay_step.py index e14ac7e..3f3fe5a 100644 --- a/src/knock_mapi/types/workflow_delay_step.py +++ b/src/knock_mapi/types/workflow_delay_step.py @@ -22,6 +22,18 @@ class Settings(BaseModel): class WorkflowDelayStep(BaseModel): + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: str + """A name for the workflow step.""" + ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -34,15 +46,3 @@ class WorkflowDelayStep(BaseModel): type: Literal["delay"] """The type of the workflow step.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_delay_step_param.py b/src/knock_mapi/types/workflow_delay_step_param.py index ffe6510..14a6dd3 100644 --- a/src/knock_mapi/types/workflow_delay_step_param.py +++ b/src/knock_mapi/types/workflow_delay_step_param.py @@ -23,6 +23,18 @@ class Settings(TypedDict, total=False): class WorkflowDelayStepParam(TypedDict, total=False): + conditions: Required[Optional[ConditionGroupParam]] + """A group of conditions to be evaluated.""" + + description: Required[Optional[str]] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Required[str] + """A name for the workflow step.""" + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -35,15 +47,3 @@ class WorkflowDelayStepParam(TypedDict, total=False): type: Required[Literal["delay"]] """The type of the workflow step.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_email_step.py b/src/knock_mapi/types/workflow_email_step.py new file mode 100644 index 0000000..36215a9 --- /dev/null +++ b/src/knock_mapi/types/workflow_email_step.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .email_template import EmailTemplate +from .condition_group import ConditionGroup +from .email_channel_settings import EmailChannelSettings + +__all__ = ["WorkflowEmailStep"] + + +class WorkflowEmailStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: EmailTemplate + """An email message template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[EmailChannelSettings] = None + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_email_step_param.py b/src/knock_mapi/types/workflow_email_step_param.py new file mode 100644 index 0000000..dda53a9 --- /dev/null +++ b/src/knock_mapi/types/workflow_email_step_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .email_template_param import EmailTemplateParam +from .condition_group_param import ConditionGroupParam +from .email_channel_settings_param import EmailChannelSettingsParam + +__all__ = ["WorkflowEmailStepParam"] + + +class WorkflowEmailStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[EmailTemplateParam] + """An email message template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[EmailChannelSettingsParam] + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_fetch_step.py b/src/knock_mapi/types/workflow_fetch_step.py index a7792b3..03e5a5a 100644 --- a/src/knock_mapi/types/workflow_fetch_step.py +++ b/src/knock_mapi/types/workflow_fetch_step.py @@ -11,13 +11,16 @@ class WorkflowFetchStep(BaseModel): + name: str + """A name for the workflow step.""" + ref: str """The reference key of the workflow step. Must be unique per workflow.""" settings: RequestTemplate """A request template for a fetch function step.""" - type: Literal["http_fetch"] + type: Literal["fetch"] """The type of the workflow step.""" conditions: Optional[ConditionGroup] = None @@ -28,6 +31,3 @@ class WorkflowFetchStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ - - name: Optional[str] = None - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_fetch_step_param.py b/src/knock_mapi/types/workflow_fetch_step_param.py index 8dd73ec..da2e56f 100644 --- a/src/knock_mapi/types/workflow_fetch_step_param.py +++ b/src/knock_mapi/types/workflow_fetch_step_param.py @@ -12,13 +12,16 @@ class WorkflowFetchStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" settings: Required[RequestTemplateParam] """A request template for a fetch function step.""" - type: Required[Literal["http_fetch"]] + type: Required[Literal["fetch"]] """The type of the workflow step.""" conditions: Optional[ConditionGroupParam] @@ -29,6 +32,3 @@ class WorkflowFetchStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ - - name: Optional[str] - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_push_step.py b/src/knock_mapi/types/workflow_push_step.py new file mode 100644 index 0000000..adeccc2 --- /dev/null +++ b/src/knock_mapi/types/workflow_push_step.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .push_template import PushTemplate +from .condition_group import ConditionGroup +from .push_channel_settings import PushChannelSettings + +__all__ = ["WorkflowPushStep"] + + +class WorkflowPushStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: PushTemplate + """A push notification template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[PushChannelSettings] = None + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_push_step_param.py b/src/knock_mapi/types/workflow_push_step_param.py new file mode 100644 index 0000000..5a4737a --- /dev/null +++ b/src/knock_mapi/types/workflow_push_step_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .push_template_param import PushTemplateParam +from .condition_group_param import ConditionGroupParam +from .push_channel_settings_param import PushChannelSettingsParam + +__all__ = ["WorkflowPushStepParam"] + + +class WorkflowPushStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[PushTemplateParam] + """A push notification template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[PushChannelSettingsParam] + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_sms_step.py b/src/knock_mapi/types/workflow_sms_step.py new file mode 100644 index 0000000..c1cd439 --- /dev/null +++ b/src/knock_mapi/types/workflow_sms_step.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .sms_template import SMSTemplate +from .condition_group import ConditionGroup +from .sms_channel_settings import SMSChannelSettings + +__all__ = ["WorkflowSMSStep"] + + +class WorkflowSMSStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: SMSTemplate + """An SMS template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[SMSChannelSettings] = None + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_sms_step_param.py b/src/knock_mapi/types/workflow_sms_step_param.py new file mode 100644 index 0000000..fb5654d --- /dev/null +++ b/src/knock_mapi/types/workflow_sms_step_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .sms_template_param import SMSTemplateParam +from .condition_group_param import ConditionGroupParam +from .sms_channel_settings_param import SMSChannelSettingsParam + +__all__ = ["WorkflowSMSStepParam"] + + +class WorkflowSMSStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[SMSTemplateParam] + """An SMS template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[SMSChannelSettingsParam] + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py index 6f8efb3..6bdb467 100644 --- a/src/knock_mapi/types/workflow_step.py +++ b/src/knock_mapi/types/workflow_step.py @@ -8,86 +8,27 @@ from .._compat import PYDANTIC_V1 from .._models import BaseModel from .send_window import SendWindow -from .sms_template import SMSTemplate -from .chat_template import ChatTemplate -from .push_template import PushTemplate -from .email_template import EmailTemplate from .condition_group import ConditionGroup -from .webhook_template import WebhookTemplate +from .workflow_sms_step import WorkflowSMSStep +from .workflow_chat_step import WorkflowChatStep +from .workflow_push_step import WorkflowPushStep from .workflow_batch_step import WorkflowBatchStep from .workflow_delay_step import WorkflowDelayStep +from .workflow_email_step import WorkflowEmailStep from .workflow_fetch_step import WorkflowFetchStep from .in_app_feed_template import InAppFeedTemplate -from .sms_channel_settings import SMSChannelSettings -from .chat_channel_settings import ChatChannelSettings -from .push_channel_settings import PushChannelSettings -from .email_channel_settings import EmailChannelSettings +from .workflow_webhook_step import WorkflowWebhookStep from .workflow_throttle_step import WorkflowThrottleStep from .in_app_feed_channel_settings import InAppFeedChannelSettings from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep -__all__ = [ - "WorkflowStep", - "WorkflowWebhookStep", - "WorkflowInAppFeedStep", - "WorkflowChatStep", - "WorkflowSMSStep", - "WorkflowPushStep", - "WorkflowEmailStep", -] +__all__ = ["WorkflowStep", "WorkflowInAppFeedStep"] -class WorkflowWebhookStep(BaseModel): - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: WebhookTemplate - """A webhook template. - - By default, a webhook step will use the request settings you configured in your - webhook channel. You can override this as you see fit on a per-step basis. - """ - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_type: Optional[Literal["http"]] = None - """The type of the channel step. Always `http` for webhook steps.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None +class WorkflowInAppFeedStep(BaseModel): + name: str """A name for the workflow step.""" - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowInAppFeedStep(BaseModel): ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -117,9 +58,6 @@ class WorkflowInAppFeedStep(BaseModel): Only used as configuration as part of a workflow channel step. """ - channel_type: Optional[Literal["in_app_feed"]] = None - """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" - conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -129,217 +67,6 @@ class WorkflowInAppFeedStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ - name: Optional[str] = None - """A name for the workflow step.""" - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowChatStep(BaseModel): - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: ChatTemplate - """A chat template.""" - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[ChatChannelSettings] = None - """Chat channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Optional[Literal["chat"]] = None - """The type of the channel step. Always `chat` for chat steps.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowSMSStep(BaseModel): - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: SMSTemplate - """An SMS template.""" - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[SMSChannelSettings] = None - """SMS channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Optional[Literal["sms"]] = None - """The type of the channel step. Always `sms` for SMS steps.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowPushStep(BaseModel): - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: PushTemplate - """A push notification template.""" - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[PushChannelSettings] = None - """Push channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Optional[Literal["push"]] = None - """The type of the channel step. Always `push` for push steps.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowEmailStep(BaseModel): - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: EmailTemplate - """An email message template.""" - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[EmailChannelSettings] = None - """Email channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Optional[Literal["email"]] = None - """The type of the channel step. Always `email` for email steps.""" - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] = None - """A name for the workflow step.""" - send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_step_param.py b/src/knock_mapi/types/workflow_step_param.py index ca4417f..e591b33 100644 --- a/src/knock_mapi/types/workflow_step_param.py +++ b/src/knock_mapi/types/workflow_step_param.py @@ -7,86 +7,27 @@ from .._compat import PYDANTIC_V1 from .send_window_param import SendWindowParam -from .sms_template_param import SMSTemplateParam -from .chat_template_param import ChatTemplateParam -from .push_template_param import PushTemplateParam -from .email_template_param import EmailTemplateParam from .condition_group_param import ConditionGroupParam -from .webhook_template_param import WebhookTemplateParam +from .workflow_sms_step_param import WorkflowSMSStepParam +from .workflow_chat_step_param import WorkflowChatStepParam +from .workflow_push_step_param import WorkflowPushStepParam from .workflow_batch_step_param import WorkflowBatchStepParam from .workflow_delay_step_param import WorkflowDelayStepParam +from .workflow_email_step_param import WorkflowEmailStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam from .in_app_feed_template_param import InAppFeedTemplateParam -from .sms_channel_settings_param import SMSChannelSettingsParam -from .chat_channel_settings_param import ChatChannelSettingsParam -from .push_channel_settings_param import PushChannelSettingsParam -from .email_channel_settings_param import EmailChannelSettingsParam +from .workflow_webhook_step_param import WorkflowWebhookStepParam from .workflow_throttle_step_param import WorkflowThrottleStepParam from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam -__all__ = [ - "WorkflowStepParam", - "WorkflowWebhookStep", - "WorkflowInAppFeedStep", - "WorkflowChatStep", - "WorkflowSMSStep", - "WorkflowPushStep", - "WorkflowEmailStep", -] +__all__ = ["WorkflowStepParam", "WorkflowInAppFeedStep"] -class WorkflowWebhookStep(TypedDict, total=False): - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[WebhookTemplateParam] - """A webhook template. - - By default, a webhook step will use the request settings you configured in your - webhook channel. You can override this as you see fit on a per-step basis. - """ - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_type: Literal["http"] - """The type of the channel step. Always `http` for webhook steps.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] +class WorkflowInAppFeedStep(TypedDict, total=False): + name: Required[str] """A name for the workflow step.""" - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowInAppFeedStep(TypedDict, total=False): ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -116,9 +57,6 @@ class WorkflowInAppFeedStep(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ - channel_type: Literal["in_app_feed"] - """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" - conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -128,217 +66,6 @@ class WorkflowInAppFeedStep(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ - name: Optional[str] - """A name for the workflow step.""" - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowChatStep(TypedDict, total=False): - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[ChatTemplateParam] - """A chat template.""" - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[ChatChannelSettingsParam] - """Chat channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Literal["chat"] - """The type of the channel step. Always `chat` for chat steps.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowSMSStep(TypedDict, total=False): - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[SMSTemplateParam] - """An SMS template.""" - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[SMSChannelSettingsParam] - """SMS channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Literal["sms"] - """The type of the channel step. Always `sms` for SMS steps.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowPushStep(TypedDict, total=False): - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[PushTemplateParam] - """A push notification template.""" - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[PushChannelSettingsParam] - """Push channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Literal["push"] - """The type of the channel step. Always `push` for push steps.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - - -class WorkflowEmailStep(TypedDict, total=False): - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[EmailTemplateParam] - """An email message template.""" - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[EmailChannelSettingsParam] - """Email channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - channel_type: Literal["email"] - """The type of the channel step. Always `email` for email steps.""" - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Optional[str] - """A name for the workflow step.""" - send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. @@ -350,12 +77,12 @@ class WorkflowEmailStep(TypedDict, total=False): WorkflowStepParam = TypeAliasType( "WorkflowStepParam", Union[ - WorkflowWebhookStep, + WorkflowWebhookStepParam, WorkflowInAppFeedStep, - WorkflowChatStep, - WorkflowSMSStep, - WorkflowPushStep, - WorkflowEmailStep, + WorkflowChatStepParam, + WorkflowSMSStepParam, + WorkflowPushStepParam, + WorkflowEmailStepParam, WorkflowDelayStepParam, WorkflowBatchStepParam, WorkflowFetchStepParam, @@ -366,12 +93,12 @@ class WorkflowEmailStep(TypedDict, total=False): ) else: WorkflowStepParam: TypeAlias = Union[ - WorkflowWebhookStep, + WorkflowWebhookStepParam, WorkflowInAppFeedStep, - WorkflowChatStep, - WorkflowSMSStep, - WorkflowPushStep, - WorkflowEmailStep, + WorkflowChatStepParam, + WorkflowSMSStepParam, + WorkflowPushStepParam, + WorkflowEmailStepParam, WorkflowDelayStepParam, WorkflowBatchStepParam, WorkflowFetchStepParam, diff --git a/src/knock_mapi/types/workflow_throttle_step.py b/src/knock_mapi/types/workflow_throttle_step.py index 6f1d4fc..74f7e98 100644 --- a/src/knock_mapi/types/workflow_throttle_step.py +++ b/src/knock_mapi/types/workflow_throttle_step.py @@ -32,6 +32,9 @@ class Settings(BaseModel): class WorkflowThrottleStep(BaseModel): + name: str + """A name for the workflow step.""" + ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -49,6 +52,3 @@ class WorkflowThrottleStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ - - name: Optional[str] = None - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_throttle_step_param.py b/src/knock_mapi/types/workflow_throttle_step_param.py index cb9dac7..9b83b4a 100644 --- a/src/knock_mapi/types/workflow_throttle_step_param.py +++ b/src/knock_mapi/types/workflow_throttle_step_param.py @@ -33,6 +33,9 @@ class Settings(TypedDict, total=False): class WorkflowThrottleStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -50,6 +53,3 @@ class WorkflowThrottleStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ - - name: Optional[str] - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step.py b/src/knock_mapi/types/workflow_trigger_workflow_step.py index f14d346..96e6e88 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step.py @@ -30,6 +30,9 @@ class Settings(BaseModel): class WorkflowTriggerWorkflowStep(BaseModel): + name: str + """A name for the workflow step.""" + ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -44,6 +47,3 @@ class WorkflowTriggerWorkflowStep(BaseModel): description: Optional[str] = None """A description for the workflow step.""" - - name: Optional[str] = None - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py index 6f78254..1469d0d 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py @@ -31,6 +31,9 @@ class Settings(TypedDict, total=False): class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -43,8 +46,5 @@ class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" - description: Optional[str] + description: str """A description for the workflow step.""" - - name: Optional[str] - """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_webhook_step.py b/src/knock_mapi/types/workflow_webhook_step.py new file mode 100644 index 0000000..c51b5ff --- /dev/null +++ b/src/knock_mapi/types/workflow_webhook_step.py @@ -0,0 +1,58 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .condition_group import ConditionGroup +from .webhook_template import WebhookTemplate + +__all__ = ["WorkflowWebhookStep"] + + +class WorkflowWebhookStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: WebhookTemplate + """A webhook template. + + By default, a webhook step will use the request settings you configured in your + webhook channel. You can override this as you see fit on a per-step basis. + """ + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_webhook_step_param.py b/src/knock_mapi/types/workflow_webhook_step_param.py new file mode 100644 index 0000000..a9ab0a2 --- /dev/null +++ b/src/knock_mapi/types/workflow_webhook_step_param.py @@ -0,0 +1,59 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .condition_group_param import ConditionGroupParam +from .webhook_template_param import WebhookTemplateParam + +__all__ = ["WorkflowWebhookStepParam"] + + +class WorkflowWebhookStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[WebhookTemplateParam] + """A webhook template. + + By default, a webhook step will use the request settings you configured in your + webhook channel. You can override this as you see fit on a per-step basis. + """ + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index 09133b6..ccb8624 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -12,6 +12,7 @@ from knock_mapi.types import ( Guide, GuideUpsertResponse, + GuideArchiveResponse, GuideActivateResponse, GuideValidateResponse, ) @@ -235,6 +236,48 @@ def test_path_params_activate_overload_2(self, client: KnockMgmt) -> None: environment="development", ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_archive(self, client: KnockMgmt) -> None: + guide = client.guides.archive( + "guide_key", + ) + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_archive(self, client: KnockMgmt) -> None: + response = client.guides.with_raw_response.archive( + "guide_key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = response.parse() + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_archive(self, client: KnockMgmt) -> None: + with client.guides.with_streaming_response.archive( + "guide_key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = response.parse() + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_archive(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + client.guides.with_raw_response.archive( + "", + ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_method_upsert(self, client: KnockMgmt) -> None: @@ -727,6 +770,48 @@ async def test_path_params_activate_overload_2(self, async_client: AsyncKnockMgm environment="development", ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_archive(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.archive( + "guide_key", + ) + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_archive(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.guides.with_raw_response.archive( + "guide_key", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + guide = await response.parse() + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_archive(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.guides.with_streaming_response.archive( + "guide_key", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + guide = await response.parse() + assert_matches_type(GuideArchiveResponse, guide, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_archive(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `guide_key` but received ''"): + await async_client.guides.with_raw_response.archive( + "", + ) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 6a7954f..e34329f 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -256,6 +256,7 @@ def test_method_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -275,6 +276,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -290,7 +292,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, - "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -301,7 +302,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", - "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -346,6 +346,7 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -369,6 +370,7 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -395,6 +397,7 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -413,6 +416,7 @@ def test_method_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -432,6 +436,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -447,7 +452,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, - "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -458,7 +462,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", - "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -500,6 +503,7 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -523,6 +527,7 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -549,6 +554,7 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -794,6 +800,7 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -813,6 +820,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -828,7 +836,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, - "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -839,7 +846,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ] }, "description": "This is a description of the channel step", - "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -884,6 +890,7 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -907,6 +914,7 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -933,6 +941,7 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -951,6 +960,7 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -970,6 +980,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -985,7 +996,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, - "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -996,7 +1006,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ] }, "description": "This is a description of the channel step", - "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -1038,6 +1047,7 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1061,6 +1071,7 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1087,6 +1098,7 @@ async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { + "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", From f2d16ba352ccce262afc098c2a9e11107fa6335d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 01:11:31 +0000 Subject: [PATCH 077/101] feat(api): add missing in-app feed step --- .stats.yml | 2 +- api.md | 1 + src/knock_mapi/types/__init__.py | 2 + .../types/workflow_in_app_feed_step.py | 61 +++++++++++++++++ .../types/workflow_in_app_feed_step_param.py | 62 ++++++++++++++++++ src/knock_mapi/types/workflow_step.py | 62 ++---------------- src/knock_mapi/types/workflow_step_param.py | 65 ++----------------- 7 files changed, 137 insertions(+), 118 deletions(-) create mode 100644 src/knock_mapi/types/workflow_in_app_feed_step.py create mode 100644 src/knock_mapi/types/workflow_in_app_feed_step_param.py diff --git a/.stats.yml b/.stats.yml index a89ee0d..022adc8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 41 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml openapi_spec_hash: 3773026857f48ace6938850a61023805 -config_hash: d70caf0fe85f6af45c65894eaf6ca490 +config_hash: 6f2ced086b09d946ca5d4ab452c55b8e diff --git a/api.md b/api.md index 79dd8da..c1a8542 100644 --- a/api.md +++ b/api.md @@ -108,6 +108,7 @@ from knock_mapi.types import ( WorkflowDelayStep, WorkflowEmailStep, WorkflowFetchStep, + WorkflowInAppFeedStep, WorkflowPushStep, WorkflowSMSStep, WorkflowStep, diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 0bfa94d..04cfd48 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -109,6 +109,7 @@ from .workflow_delay_step_param import WorkflowDelayStepParam as WorkflowDelayStepParam from .workflow_email_step_param import WorkflowEmailStepParam as WorkflowEmailStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam as WorkflowFetchStepParam +from .workflow_in_app_feed_step import WorkflowInAppFeedStep as WorkflowInAppFeedStep from .commit_commit_all_response import CommitCommitAllResponse as CommitCommitAllResponse from .email_layout_upsert_params import EmailLayoutUpsertParams as EmailLayoutUpsertParams from .in_app_feed_template_param import InAppFeedTemplateParam as InAppFeedTemplateParam @@ -143,6 +144,7 @@ from .email_layout_validate_response import EmailLayoutValidateResponse as EmailLayoutValidateResponse from .message_type_validate_response import MessageTypeValidateResponse as MessageTypeValidateResponse from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep as WorkflowTriggerWorkflowStep +from .workflow_in_app_feed_step_param import WorkflowInAppFeedStepParam as WorkflowInAppFeedStepParam from .guide_activation_url_pattern_param import GuideActivationURLPatternParam as GuideActivationURLPatternParam from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam as InAppFeedChannelSettingsParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam as WorkflowTriggerWorkflowStepParam diff --git a/src/knock_mapi/types/workflow_in_app_feed_step.py b/src/knock_mapi/types/workflow_in_app_feed_step.py new file mode 100644 index 0000000..333ea87 --- /dev/null +++ b/src/knock_mapi/types/workflow_in_app_feed_step.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from typing_extensions import Literal + +from .._models import BaseModel +from .send_window import SendWindow +from .condition_group import ConditionGroup +from .in_app_feed_template import InAppFeedTemplate +from .in_app_feed_channel_settings import InAppFeedChannelSettings + +__all__ = ["WorkflowInAppFeedStep"] + + +class WorkflowInAppFeedStep(BaseModel): + name: str + """A name for the workflow step.""" + + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + template: InAppFeedTemplate + """An in-app feed template.""" + + type: Literal["channel"] + """The type of the workflow step.""" + + channel_group_key: Optional[str] = None + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] = None + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[InAppFeedChannelSettings] = None + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[List[SendWindow]] = None + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_in_app_feed_step_param.py b/src/knock_mapi/types/workflow_in_app_feed_step_param.py new file mode 100644 index 0000000..326e3c8 --- /dev/null +++ b/src/knock_mapi/types/workflow_in_app_feed_step_param.py @@ -0,0 +1,62 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from .send_window_param import SendWindowParam +from .condition_group_param import ConditionGroupParam +from .in_app_feed_template_param import InAppFeedTemplateParam +from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam + +__all__ = ["WorkflowInAppFeedStepParam"] + + +class WorkflowInAppFeedStepParam(TypedDict, total=False): + name: Required[str] + """A name for the workflow step.""" + + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + template: Required[InAppFeedTemplateParam] + """An in-app feed template.""" + + type: Required[Literal["channel"]] + """The type of the workflow step.""" + + channel_group_key: Optional[str] + """ + The key of the channel group to which the channel step will be sending a + notification. A channel step can have either a channel key or a channel group + key, but not both. + """ + + channel_key: Optional[str] + """The key of the channel to which the channel step will be sending a notification. + + A channel step can have either a channel key or a channel group key, but not + both. + """ + + channel_overrides: Optional[InAppFeedChannelSettingsParam] + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + send_windows: Optional[Iterable[SendWindowParam]] + """A list of send window objects. + + Must include one send window object per day of the week. + """ diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py index 6bdb467..ab3501a 100644 --- a/src/knock_mapi/types/workflow_step.py +++ b/src/knock_mapi/types/workflow_step.py @@ -2,13 +2,10 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List, Union, Optional -from typing_extensions import Literal, TypeAlias, TypeAliasType +from typing import TYPE_CHECKING, Union +from typing_extensions import TypeAlias, TypeAliasType from .._compat import PYDANTIC_V1 -from .._models import BaseModel -from .send_window import SendWindow -from .condition_group import ConditionGroup from .workflow_sms_step import WorkflowSMSStep from .workflow_chat_step import WorkflowChatStep from .workflow_push_step import WorkflowPushStep @@ -16,63 +13,12 @@ from .workflow_delay_step import WorkflowDelayStep from .workflow_email_step import WorkflowEmailStep from .workflow_fetch_step import WorkflowFetchStep -from .in_app_feed_template import InAppFeedTemplate from .workflow_webhook_step import WorkflowWebhookStep from .workflow_throttle_step import WorkflowThrottleStep -from .in_app_feed_channel_settings import InAppFeedChannelSettings +from .workflow_in_app_feed_step import WorkflowInAppFeedStep from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep -__all__ = ["WorkflowStep", "WorkflowInAppFeedStep"] - - -class WorkflowInAppFeedStep(BaseModel): - name: str - """A name for the workflow step.""" - - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - template: InAppFeedTemplate - """An in-app feed template.""" - - type: Literal["channel"] - """The type of the workflow step.""" - - channel_group_key: Optional[str] = None - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] = None - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[InAppFeedChannelSettings] = None - """In-app feed channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - send_windows: Optional[List[SendWindow]] = None - """A list of send window objects. - - Must include one send window object per day of the week. - """ - +__all__ = ["WorkflowStep"] if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStep = TypeAliasType( diff --git a/src/knock_mapi/types/workflow_step_param.py b/src/knock_mapi/types/workflow_step_param.py index e591b33..b8443f4 100644 --- a/src/knock_mapi/types/workflow_step_param.py +++ b/src/knock_mapi/types/workflow_step_param.py @@ -2,12 +2,10 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Union, Iterable, Optional -from typing_extensions import Literal, Required, TypeAlias, TypedDict, TypeAliasType +from typing import TYPE_CHECKING, Union +from typing_extensions import TypeAlias, TypeAliasType from .._compat import PYDANTIC_V1 -from .send_window_param import SendWindowParam -from .condition_group_param import ConditionGroupParam from .workflow_sms_step_param import WorkflowSMSStepParam from .workflow_chat_step_param import WorkflowChatStepParam from .workflow_push_step_param import WorkflowPushStepParam @@ -15,70 +13,19 @@ from .workflow_delay_step_param import WorkflowDelayStepParam from .workflow_email_step_param import WorkflowEmailStepParam from .workflow_fetch_step_param import WorkflowFetchStepParam -from .in_app_feed_template_param import InAppFeedTemplateParam from .workflow_webhook_step_param import WorkflowWebhookStepParam from .workflow_throttle_step_param import WorkflowThrottleStepParam -from .in_app_feed_channel_settings_param import InAppFeedChannelSettingsParam +from .workflow_in_app_feed_step_param import WorkflowInAppFeedStepParam from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam -__all__ = ["WorkflowStepParam", "WorkflowInAppFeedStep"] - - -class WorkflowInAppFeedStep(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - template: Required[InAppFeedTemplateParam] - """An in-app feed template.""" - - type: Required[Literal["channel"]] - """The type of the workflow step.""" - - channel_group_key: Optional[str] - """ - The key of the channel group to which the channel step will be sending a - notification. A channel step can have either a channel key or a channel group - key, but not both. - """ - - channel_key: Optional[str] - """The key of the channel to which the channel step will be sending a notification. - - A channel step can have either a channel key or a channel group key, but not - both. - """ - - channel_overrides: Optional[InAppFeedChannelSettingsParam] - """In-app feed channel settings. - - Only used as configuration as part of a workflow channel step. - """ - - conditions: Optional[ConditionGroupParam] - """A group of conditions to be evaluated.""" - - description: Optional[str] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - send_windows: Optional[Iterable[SendWindowParam]] - """A list of send window objects. - - Must include one send window object per day of the week. - """ - +__all__ = ["WorkflowStepParam"] if TYPE_CHECKING or not PYDANTIC_V1: WorkflowStepParam = TypeAliasType( "WorkflowStepParam", Union[ WorkflowWebhookStepParam, - WorkflowInAppFeedStep, + WorkflowInAppFeedStepParam, WorkflowChatStepParam, WorkflowSMSStepParam, WorkflowPushStepParam, @@ -94,7 +41,7 @@ class WorkflowInAppFeedStep(TypedDict, total=False): else: WorkflowStepParam: TypeAlias = Union[ WorkflowWebhookStepParam, - WorkflowInAppFeedStep, + WorkflowInAppFeedStepParam, WorkflowChatStepParam, WorkflowSMSStepParam, WorkflowPushStepParam, From 8c6d93858cf5899cfb3124134a9f9fa6cc43501d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:29:31 +0000 Subject: [PATCH 078/101] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 022adc8..b4c6112 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 41 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml openapi_spec_hash: 3773026857f48ace6938850a61023805 -config_hash: 6f2ced086b09d946ca5d4ab452c55b8e +config_hash: 643ed3f0dab73b4c79c1657cc34ef298 From 4563ca203fcb58abedf61de44bc07c4721f28c94 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 14:18:29 +0000 Subject: [PATCH 079/101] feat(api): api update --- .stats.yml | 4 +-- src/knock_mapi/types/workflow_batch_step.py | 18 ++++++------ .../types/workflow_batch_step_param.py | 18 ++++++------ src/knock_mapi/types/workflow_branch_step.py | 16 +++++------ .../types/workflow_branch_step_param.py | 16 +++++------ src/knock_mapi/types/workflow_chat_step.py | 9 ++++-- .../types/workflow_chat_step_param.py | 9 ++++-- src/knock_mapi/types/workflow_delay_step.py | 24 ++++++++-------- .../types/workflow_delay_step_param.py | 24 ++++++++-------- src/knock_mapi/types/workflow_email_step.py | 9 ++++-- .../types/workflow_email_step_param.py | 9 ++++-- src/knock_mapi/types/workflow_fetch_step.py | 8 +++--- .../types/workflow_fetch_step_param.py | 8 +++--- .../types/workflow_in_app_feed_step.py | 9 ++++-- .../types/workflow_in_app_feed_step_param.py | 9 ++++-- src/knock_mapi/types/workflow_push_step.py | 9 ++++-- .../types/workflow_push_step_param.py | 9 ++++-- src/knock_mapi/types/workflow_sms_step.py | 9 ++++-- .../types/workflow_sms_step_param.py | 9 ++++-- .../types/workflow_throttle_step.py | 6 ++-- .../types/workflow_throttle_step_param.py | 6 ++-- .../types/workflow_trigger_workflow_step.py | 6 ++-- .../workflow_trigger_workflow_step_param.py | 8 +++--- src/knock_mapi/types/workflow_webhook_step.py | 9 ++++-- .../types/workflow_webhook_step_param.py | 9 ++++-- tests/api_resources/test_workflows.py | 28 ++++++------------- 26 files changed, 161 insertions(+), 137 deletions(-) diff --git a/.stats.yml b/.stats.yml index b4c6112..d5425d2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-ac77322b6a49514e5add3944d4a1c83cfa9eebc8f0d83fb4e0d3538823be1fad.yml -openapi_spec_hash: 3773026857f48ace6938850a61023805 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-11b93111b3fcec2e7fdb30e113b0deb03cea8b42c80e03be9a50ebad0f81663d.yml +openapi_spec_hash: c1732237aba39851ff1c185b8fe8458f config_hash: 643ed3f0dab73b4c79c1657cc34ef298 diff --git a/src/knock_mapi/types/workflow_batch_step.py b/src/knock_mapi/types/workflow_batch_step.py index edf6d17..ee09ea9 100644 --- a/src/knock_mapi/types/workflow_batch_step.py +++ b/src/knock_mapi/types/workflow_batch_step.py @@ -55,15 +55,6 @@ class Settings(BaseModel): class WorkflowBatchStep(BaseModel): - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -72,3 +63,12 @@ class WorkflowBatchStep(BaseModel): type: Literal["batch"] """The type of the workflow step.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_batch_step_param.py b/src/knock_mapi/types/workflow_batch_step_param.py index 5c56ca3..bea4c5b 100644 --- a/src/knock_mapi/types/workflow_batch_step_param.py +++ b/src/knock_mapi/types/workflow_batch_step_param.py @@ -56,15 +56,6 @@ class Settings(TypedDict, total=False): class WorkflowBatchStepParam(TypedDict, total=False): - description: Required[Optional[str]] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -73,3 +64,12 @@ class WorkflowBatchStepParam(TypedDict, total=False): type: Required[Literal["batch"]] """The type of the workflow step.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_branch_step.py b/src/knock_mapi/types/workflow_branch_step.py index 273d762..f6f269c 100644 --- a/src/knock_mapi/types/workflow_branch_step.py +++ b/src/knock_mapi/types/workflow_branch_step.py @@ -29,20 +29,20 @@ class WorkflowBranchStep(BaseModel): branches: List[Branch] """A list of workflow branches to be evaluated.""" - description: str + ref: str + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Literal["branch"] + """The type of step.""" + + description: Optional[str] = None """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: str + name: Optional[str] = None """A name for the workflow step.""" - ref: str - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Literal["branch"] - """The type of step.""" - from .workflow_step import WorkflowStep diff --git a/src/knock_mapi/types/workflow_branch_step_param.py b/src/knock_mapi/types/workflow_branch_step_param.py index 85e2505..aab34f8 100644 --- a/src/knock_mapi/types/workflow_branch_step_param.py +++ b/src/knock_mapi/types/workflow_branch_step_param.py @@ -28,20 +28,20 @@ class WorkflowBranchStepParam(TypedDict, total=False): branches: Required[Iterable[Branch]] """A list of workflow branches to be evaluated.""" - description: Required[str] + ref: Required[str] + """The reference key of the workflow step. Must be unique per workflow.""" + + type: Required[Literal["branch"]] + """The type of step.""" + + description: str """An arbitrary string attached to a workflow step. Useful for adding notes about the workflow for internal purposes. """ - name: Required[str] + name: Optional[str] """A name for the workflow step.""" - ref: Required[str] - """The reference key of the workflow step. Must be unique per workflow.""" - - type: Required[Literal["branch"]] - """The type of step.""" - from .workflow_step_param import WorkflowStepParam diff --git a/src/knock_mapi/types/workflow_chat_step.py b/src/knock_mapi/types/workflow_chat_step.py index 99fe775..7d79dfd 100644 --- a/src/knock_mapi/types/workflow_chat_step.py +++ b/src/knock_mapi/types/workflow_chat_step.py @@ -13,9 +13,6 @@ class WorkflowChatStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -45,6 +42,9 @@ class WorkflowChatStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["chat"]] = None + """The type of the channel step. Always `chat` for chat steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -54,6 +54,9 @@ class WorkflowChatStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_chat_step_param.py b/src/knock_mapi/types/workflow_chat_step_param.py index df5ecd9..1834ac8 100644 --- a/src/knock_mapi/types/workflow_chat_step_param.py +++ b/src/knock_mapi/types/workflow_chat_step_param.py @@ -14,9 +14,6 @@ class WorkflowChatStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,6 +43,9 @@ class WorkflowChatStepParam(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["chat"] + """The type of the channel step. Always `chat` for chat steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -55,6 +55,9 @@ class WorkflowChatStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_delay_step.py b/src/knock_mapi/types/workflow_delay_step.py index 3f3fe5a..e14ac7e 100644 --- a/src/knock_mapi/types/workflow_delay_step.py +++ b/src/knock_mapi/types/workflow_delay_step.py @@ -22,18 +22,6 @@ class Settings(BaseModel): class WorkflowDelayStep(BaseModel): - conditions: Optional[ConditionGroup] = None - """A group of conditions to be evaluated.""" - - description: Optional[str] = None - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,3 +34,15 @@ class WorkflowDelayStep(BaseModel): type: Literal["delay"] """The type of the workflow step.""" + + conditions: Optional[ConditionGroup] = None + """A group of conditions to be evaluated.""" + + description: Optional[str] = None + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_delay_step_param.py b/src/knock_mapi/types/workflow_delay_step_param.py index 14a6dd3..ffe6510 100644 --- a/src/knock_mapi/types/workflow_delay_step_param.py +++ b/src/knock_mapi/types/workflow_delay_step_param.py @@ -23,18 +23,6 @@ class Settings(TypedDict, total=False): class WorkflowDelayStepParam(TypedDict, total=False): - conditions: Required[Optional[ConditionGroupParam]] - """A group of conditions to be evaluated.""" - - description: Required[Optional[str]] - """An arbitrary string attached to a workflow step. - - Useful for adding notes about the workflow for internal purposes. - """ - - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -47,3 +35,15 @@ class WorkflowDelayStepParam(TypedDict, total=False): type: Required[Literal["delay"]] """The type of the workflow step.""" + + conditions: Optional[ConditionGroupParam] + """A group of conditions to be evaluated.""" + + description: Optional[str] + """An arbitrary string attached to a workflow step. + + Useful for adding notes about the workflow for internal purposes. + """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_email_step.py b/src/knock_mapi/types/workflow_email_step.py index 36215a9..f0cb136 100644 --- a/src/knock_mapi/types/workflow_email_step.py +++ b/src/knock_mapi/types/workflow_email_step.py @@ -13,9 +13,6 @@ class WorkflowEmailStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -45,6 +42,9 @@ class WorkflowEmailStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["email"]] = None + """The type of the channel step. Always `email` for email steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -54,6 +54,9 @@ class WorkflowEmailStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_email_step_param.py b/src/knock_mapi/types/workflow_email_step_param.py index dda53a9..3bd2f31 100644 --- a/src/knock_mapi/types/workflow_email_step_param.py +++ b/src/knock_mapi/types/workflow_email_step_param.py @@ -14,9 +14,6 @@ class WorkflowEmailStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,6 +43,9 @@ class WorkflowEmailStepParam(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["email"] + """The type of the channel step. Always `email` for email steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -55,6 +55,9 @@ class WorkflowEmailStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_fetch_step.py b/src/knock_mapi/types/workflow_fetch_step.py index 03e5a5a..a7792b3 100644 --- a/src/knock_mapi/types/workflow_fetch_step.py +++ b/src/knock_mapi/types/workflow_fetch_step.py @@ -11,16 +11,13 @@ class WorkflowFetchStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" settings: RequestTemplate """A request template for a fetch function step.""" - type: Literal["fetch"] + type: Literal["http_fetch"] """The type of the workflow step.""" conditions: Optional[ConditionGroup] = None @@ -31,3 +28,6 @@ class WorkflowFetchStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_fetch_step_param.py b/src/knock_mapi/types/workflow_fetch_step_param.py index da2e56f..8dd73ec 100644 --- a/src/knock_mapi/types/workflow_fetch_step_param.py +++ b/src/knock_mapi/types/workflow_fetch_step_param.py @@ -12,16 +12,13 @@ class WorkflowFetchStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" settings: Required[RequestTemplateParam] """A request template for a fetch function step.""" - type: Required[Literal["fetch"]] + type: Required[Literal["http_fetch"]] """The type of the workflow step.""" conditions: Optional[ConditionGroupParam] @@ -32,3 +29,6 @@ class WorkflowFetchStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_in_app_feed_step.py b/src/knock_mapi/types/workflow_in_app_feed_step.py index 333ea87..fef775c 100644 --- a/src/knock_mapi/types/workflow_in_app_feed_step.py +++ b/src/knock_mapi/types/workflow_in_app_feed_step.py @@ -13,9 +13,6 @@ class WorkflowInAppFeedStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -45,6 +42,9 @@ class WorkflowInAppFeedStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["in_app_feed"]] = None + """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -54,6 +54,9 @@ class WorkflowInAppFeedStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_in_app_feed_step_param.py b/src/knock_mapi/types/workflow_in_app_feed_step_param.py index 326e3c8..7091256 100644 --- a/src/knock_mapi/types/workflow_in_app_feed_step_param.py +++ b/src/knock_mapi/types/workflow_in_app_feed_step_param.py @@ -14,9 +14,6 @@ class WorkflowInAppFeedStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,6 +43,9 @@ class WorkflowInAppFeedStepParam(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["in_app_feed"] + """The type of the channel step. Always `in_app_feed` for in-app feed steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -55,6 +55,9 @@ class WorkflowInAppFeedStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_push_step.py b/src/knock_mapi/types/workflow_push_step.py index adeccc2..1aa9623 100644 --- a/src/knock_mapi/types/workflow_push_step.py +++ b/src/knock_mapi/types/workflow_push_step.py @@ -13,9 +13,6 @@ class WorkflowPushStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -45,6 +42,9 @@ class WorkflowPushStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["push"]] = None + """The type of the channel step. Always `push` for push steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -54,6 +54,9 @@ class WorkflowPushStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_push_step_param.py b/src/knock_mapi/types/workflow_push_step_param.py index 5a4737a..4e76176 100644 --- a/src/knock_mapi/types/workflow_push_step_param.py +++ b/src/knock_mapi/types/workflow_push_step_param.py @@ -14,9 +14,6 @@ class WorkflowPushStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,6 +43,9 @@ class WorkflowPushStepParam(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["push"] + """The type of the channel step. Always `push` for push steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -55,6 +55,9 @@ class WorkflowPushStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_sms_step.py b/src/knock_mapi/types/workflow_sms_step.py index c1cd439..1996aed 100644 --- a/src/knock_mapi/types/workflow_sms_step.py +++ b/src/knock_mapi/types/workflow_sms_step.py @@ -13,9 +13,6 @@ class WorkflowSMSStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -45,6 +42,9 @@ class WorkflowSMSStep(BaseModel): Only used as configuration as part of a workflow channel step. """ + channel_type: Optional[Literal["sms"]] = None + """The type of the channel step. Always `sms` for SMS steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -54,6 +54,9 @@ class WorkflowSMSStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_sms_step_param.py b/src/knock_mapi/types/workflow_sms_step_param.py index fb5654d..ee945a4 100644 --- a/src/knock_mapi/types/workflow_sms_step_param.py +++ b/src/knock_mapi/types/workflow_sms_step_param.py @@ -14,9 +14,6 @@ class WorkflowSMSStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,6 +43,9 @@ class WorkflowSMSStepParam(TypedDict, total=False): Only used as configuration as part of a workflow channel step. """ + channel_type: Literal["sms"] + """The type of the channel step. Always `sms` for SMS steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -55,6 +55,9 @@ class WorkflowSMSStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_throttle_step.py b/src/knock_mapi/types/workflow_throttle_step.py index 74f7e98..6f1d4fc 100644 --- a/src/knock_mapi/types/workflow_throttle_step.py +++ b/src/knock_mapi/types/workflow_throttle_step.py @@ -32,9 +32,6 @@ class Settings(BaseModel): class WorkflowThrottleStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -52,3 +49,6 @@ class WorkflowThrottleStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_throttle_step_param.py b/src/knock_mapi/types/workflow_throttle_step_param.py index 9b83b4a..cb9dac7 100644 --- a/src/knock_mapi/types/workflow_throttle_step_param.py +++ b/src/knock_mapi/types/workflow_throttle_step_param.py @@ -33,9 +33,6 @@ class Settings(TypedDict, total=False): class WorkflowThrottleStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -53,3 +50,6 @@ class WorkflowThrottleStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step.py b/src/knock_mapi/types/workflow_trigger_workflow_step.py index 96e6e88..f14d346 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step.py @@ -30,9 +30,6 @@ class Settings(BaseModel): class WorkflowTriggerWorkflowStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -47,3 +44,6 @@ class WorkflowTriggerWorkflowStep(BaseModel): description: Optional[str] = None """A description for the workflow step.""" + + name: Optional[str] = None + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py index 1469d0d..6f78254 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py @@ -31,9 +31,6 @@ class Settings(TypedDict, total=False): class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -46,5 +43,8 @@ class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" - description: str + description: Optional[str] """A description for the workflow step.""" + + name: Optional[str] + """A name for the workflow step.""" diff --git a/src/knock_mapi/types/workflow_webhook_step.py b/src/knock_mapi/types/workflow_webhook_step.py index c51b5ff..4c55377 100644 --- a/src/knock_mapi/types/workflow_webhook_step.py +++ b/src/knock_mapi/types/workflow_webhook_step.py @@ -12,9 +12,6 @@ class WorkflowWebhookStep(BaseModel): - name: str - """A name for the workflow step.""" - ref: str """The reference key of the workflow step. Must be unique per workflow.""" @@ -42,6 +39,9 @@ class WorkflowWebhookStep(BaseModel): both. """ + channel_type: Optional[Literal["http"]] = None + """The type of the channel step. Always `http` for webhook steps.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -51,6 +51,9 @@ class WorkflowWebhookStep(BaseModel): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] = None + """A name for the workflow step.""" + send_windows: Optional[List[SendWindow]] = None """A list of send window objects. diff --git a/src/knock_mapi/types/workflow_webhook_step_param.py b/src/knock_mapi/types/workflow_webhook_step_param.py index a9ab0a2..ee61ab7 100644 --- a/src/knock_mapi/types/workflow_webhook_step_param.py +++ b/src/knock_mapi/types/workflow_webhook_step_param.py @@ -13,9 +13,6 @@ class WorkflowWebhookStepParam(TypedDict, total=False): - name: Required[str] - """A name for the workflow step.""" - ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" @@ -43,6 +40,9 @@ class WorkflowWebhookStepParam(TypedDict, total=False): both. """ + channel_type: Literal["http"] + """The type of the channel step. Always `http` for webhook steps.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -52,6 +52,9 @@ class WorkflowWebhookStepParam(TypedDict, total=False): Useful for adding notes about the workflow for internal purposes. """ + name: Optional[str] + """A name for the workflow step.""" + send_windows: Optional[Iterable[SendWindowParam]] """A list of send window objects. diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index e34329f..6a7954f 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -256,7 +256,6 @@ def test_method_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -276,7 +275,6 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -292,6 +290,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -302,6 +301,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -346,7 +346,6 @@ def test_raw_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -370,7 +369,6 @@ def test_streaming_response_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -397,7 +395,6 @@ def test_path_params_upsert(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -416,7 +413,6 @@ def test_method_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -436,7 +432,6 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -452,6 +447,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -462,6 +458,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -503,7 +500,6 @@ def test_raw_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -527,7 +523,6 @@ def test_streaming_response_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -554,7 +549,6 @@ def test_path_params_validate(self, client: KnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -800,7 +794,6 @@ async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -820,7 +813,6 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -836,6 +828,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -846,6 +839,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -890,7 +884,6 @@ async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -914,7 +907,6 @@ async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -941,7 +933,6 @@ async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -960,7 +951,6 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -980,7 +970,6 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": { "markdown_body": "Hello **{{ recipient.name }}**", @@ -996,6 +985,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "channel_group_key": None, "channel_key": "in-app-feed", "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", "conditions": { "all": [ { @@ -1006,6 +996,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ] }, "description": "This is a description of the channel step", + "name": "Channel 1", "send_windows": [ { "day": "monday", @@ -1047,7 +1038,6 @@ async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1071,7 +1061,6 @@ async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) - "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", @@ -1098,7 +1087,6 @@ async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: "name": "My Workflow", "steps": [ { - "name": "Channel 1", "ref": "channel_1", "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, "type": "channel", From b3228b101a92a0dbba0f330b7992db943525b37c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:43:43 +0000 Subject: [PATCH 080/101] fix(client): close streams without requiring full consumption --- src/knock_mapi/_streaming.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/knock_mapi/_streaming.py b/src/knock_mapi/_streaming.py index 43b7d54..9cea96a 100644 --- a/src/knock_mapi/_streaming.py +++ b/src/knock_mapi/_streaming.py @@ -57,9 +57,8 @@ def __stream__(self) -> Iterator[_T]: for sse in iterator: yield process_data(data=sse.json(), cast_to=cast_to, response=response) - # Ensure the entire stream is consumed - for _sse in iterator: - ... + # As we might not fully consume the response stream, we need to close it explicitly + response.close() def __enter__(self) -> Self: return self @@ -121,9 +120,8 @@ async def __stream__(self) -> AsyncIterator[_T]: async for sse in iterator: yield process_data(data=sse.json(), cast_to=cast_to, response=response) - # Ensure the entire stream is consumed - async for _sse in iterator: - ... + # As we might not fully consume the response stream, we need to close it explicitly + await response.aclose() async def __aenter__(self) -> Self: return self From e2038a8ccc329b3661f667d48f9f3b0422dd902a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:02:54 +0000 Subject: [PATCH 081/101] chore(internal/tests): avoid race condition with implicit client cleanup --- tests/test_client.py | 356 ++++++++++++++++++++++++------------------- 1 file changed, 196 insertions(+), 160 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 96a8cf8..b47066f 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -51,51 +51,49 @@ def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: class TestKnockMgmt: - client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter) -> None: + def test_raw_response(self, respx_mock: MockRouter, client: KnockMgmt) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: KnockMgmt) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, client: KnockMgmt) -> None: + copied = client.copy() + assert id(copied) != id(client) - copied = self.client.copy(service_token="another My Service Token") + copied = client.copy(service_token="another My Service Token") assert copied.service_token == "another My Service Token" - assert self.client.service_token == "My Service Token" + assert client.service_token == "My Service Token" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, client: KnockMgmt) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(client.timeout, httpx.Timeout) def test_copy_default_headers(self) -> None: client = KnockMgmt( @@ -133,6 +131,7 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() def test_copy_default_query(self) -> None: client = KnockMgmt( @@ -173,13 +172,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + client.close() + + def test_copy_signature(self, client: KnockMgmt) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -190,12 +191,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, client: KnockMgmt) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -252,14 +253,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + def test_request_timeout(self, client: KnockMgmt) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(100.0) @@ -272,6 +271,8 @@ def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + client.close() + def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: @@ -286,6 +287,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + client.close() + # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = KnockMgmt( @@ -299,6 +302,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + client.close() + # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = KnockMgmt( @@ -312,6 +317,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + client.close() + async def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): async with httpx.AsyncClient() as http_client: @@ -323,17 +330,17 @@ async def test_invalid_http_client(self) -> None: ) def test_default_headers_option(self) -> None: - client = KnockMgmt( + test_client = KnockMgmt( base_url=base_url, service_token=service_token, _strict_response_validation=True, default_headers={"X-Foo": "bar"}, ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = KnockMgmt( + test_client2 = KnockMgmt( base_url=base_url, service_token=service_token, _strict_response_validation=True, @@ -342,10 +349,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + test_client.close() + test_client2.close() + def test_validate_headers(self) -> None: client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -377,8 +387,10 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + client.close() + + def test_request_extra_json(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -389,7 +401,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -400,7 +412,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -411,8 +423,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -422,7 +434,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -433,8 +445,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -447,7 +459,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -461,7 +473,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -504,7 +516,7 @@ def test_multipart_repeating_array(self, client: KnockMgmt) -> None: ] @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter) -> None: + def test_basic_union_response(self, respx_mock: MockRouter, client: KnockMgmt) -> None: class Model1(BaseModel): name: str @@ -513,12 +525,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + def test_union_response_different_types(self, respx_mock: MockRouter, client: KnockMgmt) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -529,18 +541,18 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: KnockMgmt) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -556,7 +568,7 @@ class Model(BaseModel): ) ) - response = self.client.get("/foo", cast_to=Model) + response = client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @@ -570,6 +582,8 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" + client.close() + def test_base_url_env(self) -> None: with update_env(KNOCK_MGMT_BASE_URL="http://localhost:5000/from/env"): client = KnockMgmt(service_token=service_token, _strict_response_validation=True) @@ -601,6 +615,7 @@ def test_base_url_trailing_slash(self, client: KnockMgmt) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -628,6 +643,7 @@ def test_base_url_no_trailing_slash(self, client: KnockMgmt) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + client.close() @pytest.mark.parametrize( "client", @@ -655,35 +671,36 @@ def test_absolute_request_url(self, client: KnockMgmt) -> None: ), ) assert request.url == "https://myapi.com/foo" + client.close() def test_copied_client_does_not_close_http(self) -> None: - client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - assert not client.is_closed() + test_client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied - assert not client.is_closed() + assert not test_client.is_closed() def test_client_context_manager(self) -> None: - client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - with client as c2: - assert c2 is client + test_client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + def test_client_response_validation_error(self, respx_mock: MockRouter, client: KnockMgmt) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - self.client.get("/foo", cast_to=Model) + client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -708,11 +725,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=False) + non_strict_client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=False) - response = client.get("/foo", cast_to=Model) + response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + strict_client.close() + non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -735,9 +755,9 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = KnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: KnockMgmt + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) @@ -847,83 +867,77 @@ def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - def test_follow_redirects(self, respx_mock: MockRouter) -> None: + def test_follow_redirects(self, respx_mock: MockRouter, client: KnockMgmt) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: KnockMgmt) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - self.client.post( - "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response - ) + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" class TestAsyncKnockMgmt: - client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response(self, respx_mock: MockRouter) -> None: + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, async_client: AsyncKnockMgmt) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) - copied = self.client.copy(service_token="another My Service Token") + copied = async_client.copy(service_token="another My Service Token") assert copied.service_token == "another My Service Token" - assert self.client.service_token == "My Service Token" + assert async_client.service_token == "My Service Token" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, async_client: AsyncKnockMgmt) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = async_client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert async_client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(async_client.timeout, httpx.Timeout) - def test_copy_default_headers(self) -> None: + async def test_copy_default_headers(self) -> None: client = AsyncKnockMgmt( base_url=base_url, service_token=service_token, @@ -959,8 +973,9 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() - def test_copy_default_query(self) -> None: + async def test_copy_default_query(self) -> None: client = AsyncKnockMgmt( base_url=base_url, service_token=service_token, @@ -999,13 +1014,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + await client.close() + + def test_copy_signature(self, async_client: AsyncKnockMgmt) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + async_client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -1016,12 +1033,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, async_client: AsyncKnockMgmt) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = async_client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -1078,12 +1095,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - async def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + async def test_request_timeout(self, async_client: AsyncKnockMgmt) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( + request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) ) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -1098,6 +1115,8 @@ async def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + await client.close() + async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: @@ -1112,6 +1131,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + await client.close() + # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncKnockMgmt( @@ -1125,6 +1146,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + await client.close() + # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncKnockMgmt( @@ -1138,6 +1161,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + await client.close() + def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): with httpx.Client() as http_client: @@ -1148,18 +1173,18 @@ def test_invalid_http_client(self) -> None: http_client=cast(Any, http_client), ) - def test_default_headers_option(self) -> None: - client = AsyncKnockMgmt( + async def test_default_headers_option(self) -> None: + test_client = AsyncKnockMgmt( base_url=base_url, service_token=service_token, _strict_response_validation=True, default_headers={"X-Foo": "bar"}, ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = AsyncKnockMgmt( + test_client2 = AsyncKnockMgmt( base_url=base_url, service_token=service_token, _strict_response_validation=True, @@ -1168,10 +1193,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + await test_client.close() + await test_client2.close() + def test_validate_headers(self) -> None: client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) request = client._build_request(FinalRequestOptions(method="get", url="/foo")) @@ -1182,7 +1210,7 @@ def test_validate_headers(self) -> None: client2 = AsyncKnockMgmt(base_url=base_url, service_token=None, _strict_response_validation=True) _ = client2 - def test_default_query_option(self) -> None: + async def test_default_query_option(self) -> None: client = AsyncKnockMgmt( base_url=base_url, service_token=service_token, @@ -1203,8 +1231,10 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + await client.close() + + def test_request_extra_json(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1215,7 +1245,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1226,7 +1256,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1237,8 +1267,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1248,7 +1278,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1259,8 +1289,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: KnockMgmt) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1273,7 +1303,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo"} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1287,7 +1317,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2"} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1330,7 +1360,7 @@ def test_multipart_repeating_array(self, async_client: AsyncKnockMgmt) -> None: ] @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: class Model1(BaseModel): name: str @@ -1339,12 +1369,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -1355,18 +1385,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncKnockMgmt + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -1382,11 +1414,11 @@ class Model(BaseModel): ) ) - response = await self.client.get("/foo", cast_to=Model) + response = await async_client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 - def test_base_url_setter(self) -> None: + async def test_base_url_setter(self) -> None: client = AsyncKnockMgmt( base_url="https://example.com/from_init", service_token=service_token, _strict_response_validation=True ) @@ -1396,7 +1428,9 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" - def test_base_url_env(self) -> None: + await client.close() + + async def test_base_url_env(self) -> None: with update_env(KNOCK_MGMT_BASE_URL="http://localhost:5000/from/env"): client = AsyncKnockMgmt(service_token=service_token, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @@ -1418,7 +1452,7 @@ def test_base_url_env(self) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_trailing_slash(self, client: AsyncKnockMgmt) -> None: + async def test_base_url_trailing_slash(self, client: AsyncKnockMgmt) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1427,6 +1461,7 @@ def test_base_url_trailing_slash(self, client: AsyncKnockMgmt) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1445,7 +1480,7 @@ def test_base_url_trailing_slash(self, client: AsyncKnockMgmt) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_no_trailing_slash(self, client: AsyncKnockMgmt) -> None: + async def test_base_url_no_trailing_slash(self, client: AsyncKnockMgmt) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1454,6 +1489,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncKnockMgmt) -> None: ), ) assert request.url == "http://localhost:5000/custom/path/foo" + await client.close() @pytest.mark.parametrize( "client", @@ -1472,7 +1508,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncKnockMgmt) -> None: ], ids=["standard", "custom http client"], ) - def test_absolute_request_url(self, client: AsyncKnockMgmt) -> None: + async def test_absolute_request_url(self, client: AsyncKnockMgmt) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1481,37 +1517,37 @@ def test_absolute_request_url(self, client: AsyncKnockMgmt) -> None: ), ) assert request.url == "https://myapi.com/foo" + await client.close() async def test_copied_client_does_not_close_http(self) -> None: - client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - assert not client.is_closed() + test_client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied await asyncio.sleep(0.2) - assert not client.is_closed() + assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - async with client as c2: - assert c2 is client + test_client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - await self.client.get("/foo", cast_to=Model) + await async_client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -1525,7 +1561,6 @@ async def test_client_max_retries_validation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): name: str @@ -1537,11 +1572,16 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=False) + non_strict_client = AsyncKnockMgmt( + base_url=base_url, service_token=service_token, _strict_response_validation=False + ) - response = await client.get("/foo", cast_to=Model) + response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + await strict_client.close() + await non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -1564,19 +1604,17 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - @pytest.mark.asyncio - async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True) - + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncKnockMgmt + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("knock_mapi._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( self, @@ -1608,7 +1646,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("knock_mapi._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_omit_retry_count_header( self, async_client: AsyncKnockMgmt, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1634,7 +1671,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("knock_mapi._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_overwrite_retry_count_header( self, async_client: AsyncKnockMgmt, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1684,26 +1720,26 @@ async def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncKnockMgmt) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - await self.client.post( + await async_client.post( "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response ) From ee64945b8a4aa9fe9a6fc275e9128a9467c691fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 16:11:52 +0000 Subject: [PATCH 082/101] chore(internal): grammar fix (it's -> its) --- src/knock_mapi/_utils/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knock_mapi/_utils/_utils.py b/src/knock_mapi/_utils/_utils.py index 50d5926..eec7f4a 100644 --- a/src/knock_mapi/_utils/_utils.py +++ b/src/knock_mapi/_utils/_utils.py @@ -133,7 +133,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: # Type safe methods for narrowing types with TypeVars. # The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], # however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in it's place. +# care about the contained types we can safely use `object` in its place. # # There are two separate functions defined, `is_*` and `is_*_t` for different use cases. # `is_*` is for when you're dealing with an unknown input From 8e266a26c0677603f2aa2e98b1bd59b29ccd0b46 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:29:29 +0000 Subject: [PATCH 083/101] chore(package): drop Python 3.8 support --- README.md | 4 ++-- pyproject.toml | 5 ++--- src/knock_mapi/_utils/_sync.py | 34 +++------------------------------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 91e6336..46682cb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PyPI version](https://img.shields.io/pypi/v/knock_mapi.svg?label=pypi%20(stable))](https://pypi.org/project/knock_mapi/) -The Knock Mgmt Python library provides convenient access to the Knock Mgmt REST API from any Python 3.8+ +The Knock Mgmt Python library provides convenient access to the Knock Mgmt REST API from any Python 3.9+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -473,7 +473,7 @@ print(knock_mapi.__version__) ## Requirements -Python 3.8 or higher. +Python 3.9 or higher. ## Contributing diff --git a/pyproject.toml b/pyproject.toml index be26e0c..2e64eae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,11 +15,10 @@ dependencies = [ "distro>=1.7.0, <2", "sniffio", ] -requires-python = ">= 3.8" +requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -141,7 +140,7 @@ filterwarnings = [ # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.8" +pythonVersion = "3.9" exclude = [ "_dev", diff --git a/src/knock_mapi/_utils/_sync.py b/src/knock_mapi/_utils/_sync.py index ad7ec71..f6027c1 100644 --- a/src/knock_mapi/_utils/_sync.py +++ b/src/knock_mapi/_utils/_sync.py @@ -1,10 +1,8 @@ from __future__ import annotations -import sys import asyncio import functools -import contextvars -from typing import Any, TypeVar, Callable, Awaitable +from typing import TypeVar, Callable, Awaitable from typing_extensions import ParamSpec import anyio @@ -15,34 +13,11 @@ T_ParamSpec = ParamSpec("T_ParamSpec") -if sys.version_info >= (3, 9): - _asyncio_to_thread = asyncio.to_thread -else: - # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread - # for Python 3.8 support - async def _asyncio_to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs - ) -> Any: - """Asynchronously run function *func* in a separate thread. - - Any *args and **kwargs supplied for this function are directly passed - to *func*. Also, the current :class:`contextvars.Context` is propagated, - allowing context variables from the main thread to be accessed in the - separate thread. - - Returns a coroutine that can be awaited to get the eventual result of *func*. - """ - loop = asyncio.events.get_running_loop() - ctx = contextvars.copy_context() - func_call = functools.partial(ctx.run, func, *args, **kwargs) - return await loop.run_in_executor(None, func_call) - - async def to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> T_Retval: if sniffio.current_async_library() == "asyncio": - return await _asyncio_to_thread(func, *args, **kwargs) + return await asyncio.to_thread(func, *args, **kwargs) return await anyio.to_thread.run_sync( functools.partial(func, *args, **kwargs), @@ -53,10 +28,7 @@ async def to_thread( def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ Take a blocking function and create an async one that receives the same - positional and keyword arguments. For python version 3.9 and above, it uses - asyncio.to_thread to run the function in a separate thread. For python version - 3.8, it uses locally defined copy of the asyncio.to_thread function which was - introduced in python 3.9. + positional and keyword arguments. Usage: From 50bf20a54a3ed5b684f2160016bdc0432c1436a6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:36:17 +0000 Subject: [PATCH 084/101] fix: compat with Python 3.14 --- src/knock_mapi/_models.py | 11 ++++++++--- tests/test_models.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index 6a3cd1d..fcec2cf 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -2,6 +2,7 @@ import os import inspect +import weakref from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( @@ -573,6 +574,9 @@ class CachedDiscriminatorType(Protocol): __discriminator__: DiscriminatorDetails +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -615,8 +619,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached discriminator_field_name: str | None = None @@ -669,7 +674,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + DISCRIMINATOR_CACHE.setdefault(union, details) return details diff --git a/tests/test_models.py b/tests/test_models.py index 522ff87..f9af039 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,7 +9,7 @@ from knock_mapi._utils import PropertyInfo from knock_mapi._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from knock_mapi._models import BaseModel, construct_type +from knock_mapi._models import DISCRIMINATOR_CACHE, BaseModel, construct_type class BasicModel(BaseModel): @@ -809,7 +809,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert not DISCRIMINATOR_CACHE.get(UnionType) m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -818,7 +818,7 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None m = construct_type( @@ -830,7 +830,7 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator @pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") From 7d0d80e4bfd30d6f569003b346ab60b218f6a9e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 14:35:57 +0000 Subject: [PATCH 085/101] fix(compat): update signatures of `model_dump` and `model_dump_json` for Pydantic v1 --- src/knock_mapi/_models.py | 41 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py index fcec2cf..ca9500b 100644 --- a/src/knock_mapi/_models.py +++ b/src/knock_mapi/_models.py @@ -257,15 +257,16 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, - serialize_as_any: bool = False, fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -273,16 +274,24 @@ def model_dump( Args: mode: The mode in which `to_python` should run. - If mode is 'json', the dictionary will only contain JSON serializable types. - If mode is 'python', the dictionary may contain any Python objects. - include: A list of fields to include in the output. - exclude: A list of fields to exclude from the output. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that are unset or None from the output. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - round_trip: Whether to enable serialization and deserialization round-trip support. - warnings: Whether to log warnings when invalid fields are encountered. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. Returns: A dictionary representation of the model. @@ -299,6 +308,8 @@ def model_dump( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, @@ -315,15 +326,17 @@ def model_dump_json( self, *, indent: int | None = None, + ensure_ascii: bool = False, include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: @@ -355,6 +368,10 @@ def model_dump_json( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, From cdf34d7231f4907b906279d4f80b57d695acc3d2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 19:39:10 +0000 Subject: [PATCH 086/101] feat(api): api update --- .stats.yml | 4 +- src/knock_mapi/resources/commits.py | 20 ++++ src/knock_mapi/resources/email_layouts.py | 50 +++++++++- src/knock_mapi/resources/guides.py | 84 +++++++++++++++- src/knock_mapi/resources/message_types.py | 50 +++++++++- src/knock_mapi/resources/partials.py | 52 +++++++++- src/knock_mapi/resources/translations.py | 50 +++++++++- src/knock_mapi/resources/variables.py | 10 ++ src/knock_mapi/resources/workflows/steps.py | 20 +++- .../resources/workflows/workflows.py | 98 +++++++++++++++++-- .../types/commit_commit_all_params.py | 6 ++ src/knock_mapi/types/commit_list_params.py | 6 ++ .../types/email_layout_list_params.py | 6 ++ .../types/email_layout_retrieve_params.py | 6 ++ .../types/email_layout_upsert_params.py | 6 ++ .../types/email_layout_validate_params.py | 6 ++ src/knock_mapi/types/guide_activate_params.py | 12 +++ src/knock_mapi/types/guide_list_params.py | 6 ++ src/knock_mapi/types/guide_retrieve_params.py | 6 ++ src/knock_mapi/types/guide_upsert_params.py | 6 ++ src/knock_mapi/types/guide_validate_params.py | 6 ++ .../types/message_type_list_params.py | 6 ++ .../types/message_type_retrieve_params.py | 6 ++ .../types/message_type_upsert_params.py | 6 ++ .../types/message_type_validate_params.py | 6 ++ src/knock_mapi/types/partial_list_params.py | 6 ++ .../types/partial_retrieve_params.py | 6 ++ src/knock_mapi/types/partial_upsert_params.py | 6 ++ .../types/partial_validate_params.py | 6 ++ .../types/translation_list_params.py | 6 ++ .../types/translation_retrieve_params.py | 6 ++ .../types/translation_upsert_params.py | 6 ++ .../types/translation_validate_params.py | 6 ++ src/knock_mapi/types/variable_list_params.py | 6 ++ .../types/workflow_activate_params.py | 6 ++ src/knock_mapi/types/workflow_list_params.py | 6 ++ .../types/workflow_retrieve_params.py | 6 ++ src/knock_mapi/types/workflow_run_params.py | 6 ++ .../types/workflow_upsert_params.py | 6 ++ .../types/workflow_validate_params.py | 6 ++ .../workflows/step_preview_template_params.py | 6 ++ tests/api_resources/test_commits.py | 4 + tests/api_resources/test_email_layouts.py | 8 ++ tests/api_resources/test_guides.py | 32 ++++++ tests/api_resources/test_message_types.py | 8 ++ tests/api_resources/test_partials.py | 8 ++ tests/api_resources/test_translations.py | 34 +++++++ tests/api_resources/test_variables.py | 2 + tests/api_resources/test_workflows.py | 32 ++++++ tests/api_resources/workflows/test_steps.py | 2 + 50 files changed, 738 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index d5425d2..f2bcb18 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-11b93111b3fcec2e7fdb30e113b0deb03cea8b42c80e03be9a50ebad0f81663d.yml -openapi_spec_hash: c1732237aba39851ff1c185b8fe8458f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-310a2e25c41149fe061e3c53d969392ca8bf4335762a32ce5b5d376990f4037d.yml +openapi_spec_hash: 0399fa6824e38cdb61fc9e8bd55d9622 config_hash: 643ed3f0dab73b4c79c1657cc34ef298 diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index d1253cf..cb97fc9 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -87,6 +87,7 @@ def list( environment: str, after: str | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, @@ -114,6 +115,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + limit: The number of entries to fetch per-page. promoted: Whether to show commits in the given environment that have not been promoted to @@ -148,6 +152,7 @@ def list( "environment": environment, "after": after, "before": before, + "branch": branch, "limit": limit, "promoted": promoted, "resource_id": resource_id, @@ -163,6 +168,7 @@ def commit_all( self, *, environment: str, + branch: str | Omit = omit, commit_message: str | Omit = omit, resource_id: str | Omit = omit, resource_type: Union[ @@ -183,6 +189,9 @@ def commit_all( Args: environment: The environment slug. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit_message: An optional message to include in a commit. resource_id: Filter changes to commit by resource identifier. Must be used together with @@ -209,6 +218,7 @@ def commit_all( query=maybe_transform( { "environment": environment, + "branch": branch, "commit_message": commit_message, "resource_id": resource_id, "resource_type": resource_type, @@ -376,6 +386,7 @@ def list( environment: str, after: str | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, limit: int | Omit = omit, promoted: bool | Omit = omit, resource_id: str | Omit = omit, @@ -403,6 +414,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + limit: The number of entries to fetch per-page. promoted: Whether to show commits in the given environment that have not been promoted to @@ -437,6 +451,7 @@ def list( "environment": environment, "after": after, "before": before, + "branch": branch, "limit": limit, "promoted": promoted, "resource_id": resource_id, @@ -452,6 +467,7 @@ async def commit_all( self, *, environment: str, + branch: str | Omit = omit, commit_message: str | Omit = omit, resource_id: str | Omit = omit, resource_type: Union[ @@ -472,6 +488,9 @@ async def commit_all( Args: environment: The environment slug. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit_message: An optional message to include in a commit. resource_id: Filter changes to commit by resource identifier. Must be used together with @@ -498,6 +517,7 @@ async def commit_all( query=await async_maybe_transform( { "environment": environment, + "branch": branch, "commit_message": commit_message, "resource_id": resource_id, "resource_type": resource_type, diff --git a/src/knock_mapi/resources/email_layouts.py b/src/knock_mapi/resources/email_layouts.py index e9b34f5..ffa300d 100644 --- a/src/knock_mapi/resources/email_layouts.py +++ b/src/knock_mapi/resources/email_layouts.py @@ -55,6 +55,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -71,6 +72,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -95,6 +99,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, email_layout_retrieve_params.EmailLayoutRetrieveParams, @@ -110,6 +115,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -131,6 +137,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -158,6 +167,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -174,6 +184,7 @@ def upsert( environment: str, email_layout: email_layout_upsert_params.EmailLayout, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -195,6 +206,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -221,6 +235,7 @@ def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -236,6 +251,7 @@ def validate( *, environment: str, email_layout: email_layout_validate_params.EmailLayout, + branch: 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, @@ -253,6 +269,9 @@ def validate( email_layout: A request to update or create an email layout. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -274,7 +293,11 @@ def validate( extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"environment": environment}, email_layout_validate_params.EmailLayoutValidateParams + { + "environment": environment, + "branch": branch, + }, + email_layout_validate_params.EmailLayoutValidateParams, ), ), cast_to=EmailLayoutValidateResponse, @@ -307,6 +330,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -323,6 +347,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -347,6 +374,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, email_layout_retrieve_params.EmailLayoutRetrieveParams, @@ -362,6 +390,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -383,6 +412,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -410,6 +442,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -426,6 +459,7 @@ async def upsert( environment: str, email_layout: email_layout_upsert_params.EmailLayout, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -447,6 +481,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -475,6 +512,7 @@ async def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -490,6 +528,7 @@ async def validate( *, environment: str, email_layout: email_layout_validate_params.EmailLayout, + branch: 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, @@ -507,6 +546,9 @@ async def validate( email_layout: A request to update or create an email layout. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -528,7 +570,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, email_layout_validate_params.EmailLayoutValidateParams + { + "environment": environment, + "branch": branch, + }, + email_layout_validate_params.EmailLayoutValidateParams, ), ), cast_to=EmailLayoutValidateResponse, diff --git a/src/knock_mapi/resources/guides.py b/src/knock_mapi/resources/guides.py index b4cfc5e..7cc4044 100644 --- a/src/knock_mapi/resources/guides.py +++ b/src/knock_mapi/resources/guides.py @@ -62,6 +62,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -78,6 +79,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -102,6 +106,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, guide_retrieve_params.GuideRetrieveParams, @@ -117,6 +122,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -138,6 +144,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -165,6 +174,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -181,6 +191,7 @@ def activate( *, environment: str, status: bool, + branch: 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, @@ -201,6 +212,9 @@ def activate( status: Whether to activate or deactivate the guide. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -217,6 +231,7 @@ def activate( guide_key: str, *, environment: str, + branch: str | Omit = omit, from_: Union[str, datetime] | Omit = omit, until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -237,6 +252,9 @@ def activate( Args: environment: The environment slug. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + from_: When to activate the guide. If provided, the guide will be scheduled to activate at this time. Must be in ISO 8601 UTC format. @@ -260,6 +278,7 @@ def activate( *, environment: str, status: bool | Omit = omit, + branch: str | Omit = omit, from_: Union[str, datetime] | Omit = omit, until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -286,7 +305,13 @@ def activate( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, guide_activate_params.GuideActivateParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + guide_activate_params.GuideActivateParams, + ), ), cast_to=GuideActivateResponse, ) @@ -331,6 +356,7 @@ def upsert( environment: str, guide: guide_upsert_params.Guide, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -352,6 +378,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -378,6 +407,7 @@ def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -393,6 +423,7 @@ def validate( *, environment: str, guide: guide_validate_params.Guide, + branch: 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, @@ -410,6 +441,9 @@ def validate( guide: A request to create or update a guide. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -428,7 +462,13 @@ def validate( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, guide_validate_params.GuideValidateParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + guide_validate_params.GuideValidateParams, + ), ), cast_to=GuideValidateResponse, ) @@ -460,6 +500,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -476,6 +517,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -500,6 +544,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, guide_retrieve_params.GuideRetrieveParams, @@ -515,6 +560,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -536,6 +582,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -563,6 +612,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -579,6 +629,7 @@ async def activate( *, environment: str, status: bool, + branch: 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, @@ -599,6 +650,9 @@ async def activate( status: Whether to activate or deactivate the guide. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -615,6 +669,7 @@ async def activate( guide_key: str, *, environment: str, + branch: str | Omit = omit, from_: Union[str, datetime] | Omit = omit, until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -635,6 +690,9 @@ async def activate( Args: environment: The environment slug. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + from_: When to activate the guide. If provided, the guide will be scheduled to activate at this time. Must be in ISO 8601 UTC format. @@ -658,6 +716,7 @@ async def activate( *, environment: str, status: bool | Omit = omit, + branch: str | Omit = omit, from_: Union[str, datetime] | Omit = omit, until: Union[str, datetime] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -685,7 +744,11 @@ async def activate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, guide_activate_params.GuideActivateParams + { + "environment": environment, + "branch": branch, + }, + guide_activate_params.GuideActivateParams, ), ), cast_to=GuideActivateResponse, @@ -731,6 +794,7 @@ async def upsert( environment: str, guide: guide_upsert_params.Guide, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -752,6 +816,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -778,6 +845,7 @@ async def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -793,6 +861,7 @@ async def validate( *, environment: str, guide: guide_validate_params.Guide, + branch: 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, @@ -810,6 +879,9 @@ async def validate( guide: A request to create or update a guide. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -829,7 +901,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, guide_validate_params.GuideValidateParams + { + "environment": environment, + "branch": branch, + }, + guide_validate_params.GuideValidateParams, ), ), cast_to=GuideValidateResponse, diff --git a/src/knock_mapi/resources/message_types.py b/src/knock_mapi/resources/message_types.py index e345e85..dec0f2e 100644 --- a/src/knock_mapi/resources/message_types.py +++ b/src/knock_mapi/resources/message_types.py @@ -55,6 +55,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -71,6 +72,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -95,6 +99,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, message_type_retrieve_params.MessageTypeRetrieveParams, @@ -110,6 +115,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -131,6 +137,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -158,6 +167,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -174,6 +184,7 @@ def upsert( environment: str, message_type: message_type_upsert_params.MessageType, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -195,6 +206,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -221,6 +235,7 @@ def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -236,6 +251,7 @@ def validate( *, environment: str, message_type: message_type_validate_params.MessageType, + branch: 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, @@ -254,6 +270,9 @@ def validate( message_type: A request to create a message type. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -275,7 +294,11 @@ def validate( extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"environment": environment}, message_type_validate_params.MessageTypeValidateParams + { + "environment": environment, + "branch": branch, + }, + message_type_validate_params.MessageTypeValidateParams, ), ), cast_to=MessageTypeValidateResponse, @@ -308,6 +331,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -324,6 +348,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -348,6 +375,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, message_type_retrieve_params.MessageTypeRetrieveParams, @@ -363,6 +391,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -384,6 +413,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -411,6 +443,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -427,6 +460,7 @@ async def upsert( environment: str, message_type: message_type_upsert_params.MessageType, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -448,6 +482,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -476,6 +513,7 @@ async def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -491,6 +529,7 @@ async def validate( *, environment: str, message_type: message_type_validate_params.MessageType, + branch: 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, @@ -509,6 +548,9 @@ async def validate( message_type: A request to create a message type. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -530,7 +572,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, message_type_validate_params.MessageTypeValidateParams + { + "environment": environment, + "branch": branch, + }, + message_type_validate_params.MessageTypeValidateParams, ), ), cast_to=MessageTypeValidateResponse, diff --git a/src/knock_mapi/resources/partials.py b/src/knock_mapi/resources/partials.py index 6744e3d..90eed9b 100644 --- a/src/knock_mapi/resources/partials.py +++ b/src/knock_mapi/resources/partials.py @@ -50,6 +50,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -66,6 +67,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -90,6 +94,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, partial_retrieve_params.PartialRetrieveParams, @@ -105,6 +110,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -126,6 +132,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -153,6 +162,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -169,6 +179,7 @@ def upsert( environment: str, partial: partial_upsert_params.Partial, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -190,6 +201,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -216,6 +230,7 @@ def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -231,6 +246,7 @@ def validate( *, environment: str, partial: partial_validate_params.Partial, + branch: 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, @@ -248,6 +264,9 @@ def validate( partial: A partial object with attributes to update or create a partial. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -266,7 +285,13 @@ def validate( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, partial_validate_params.PartialValidateParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + partial_validate_params.PartialValidateParams, + ), ), cast_to=PartialValidateResponse, ) @@ -298,6 +323,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -314,6 +340,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -338,6 +367,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, partial_retrieve_params.PartialRetrieveParams, @@ -353,6 +383,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -374,6 +405,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -401,6 +435,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -417,6 +452,7 @@ async def upsert( environment: str, partial: partial_upsert_params.Partial, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -438,6 +474,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -464,6 +503,7 @@ async def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -479,6 +519,7 @@ async def validate( *, environment: str, partial: partial_validate_params.Partial, + branch: 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, @@ -496,6 +537,9 @@ async def validate( partial: A partial object with attributes to update or create a partial. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -515,7 +559,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, partial_validate_params.PartialValidateParams + { + "environment": environment, + "branch": branch, + }, + partial_validate_params.PartialValidateParams, ), ), cast_to=PartialValidateResponse, diff --git a/src/knock_mapi/resources/translations.py b/src/knock_mapi/resources/translations.py index ba685fd..46a9dd5 100644 --- a/src/knock_mapi/resources/translations.py +++ b/src/knock_mapi/resources/translations.py @@ -58,6 +58,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, namespace: str | Omit = omit, @@ -76,6 +77,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + format: Optionally specify the returned content format. Supports 'json' and 'po'. Defaults to 'json'. @@ -105,6 +109,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "format": format, "hide_uncommitted_changes": hide_uncommitted_changes, "namespace": namespace, @@ -122,6 +127,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, limit: int | Omit = omit, @@ -148,6 +154,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + format: Optionally specify the returned content format. Supports 'json' and 'po'. Defaults to 'json'. @@ -182,6 +191,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "format": format, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, @@ -202,6 +212,7 @@ def upsert( namespace: str, translation: translation_upsert_params.Translation, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, @@ -229,6 +240,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -259,6 +273,7 @@ def upsert( "environment": environment, "namespace": namespace, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, "format": format, @@ -275,6 +290,7 @@ def validate( *, environment: str, translation: translation_validate_params.Translation, + branch: 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, @@ -294,6 +310,9 @@ def validate( translation: A translation object with a content attribute used to update or create a translation. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -313,7 +332,11 @@ def validate( extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"environment": environment}, translation_validate_params.TranslationValidateParams + { + "environment": environment, + "branch": branch, + }, + translation_validate_params.TranslationValidateParams, ), ), cast_to=TranslationValidateResponse, @@ -346,6 +369,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, namespace: str | Omit = omit, @@ -364,6 +388,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + format: Optionally specify the returned content format. Supports 'json' and 'po'. Defaults to 'json'. @@ -393,6 +420,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "format": format, "hide_uncommitted_changes": hide_uncommitted_changes, "namespace": namespace, @@ -410,6 +438,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, limit: int | Omit = omit, @@ -436,6 +465,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + format: Optionally specify the returned content format. Supports 'json' and 'po'. Defaults to 'json'. @@ -470,6 +502,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "format": format, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, @@ -490,6 +523,7 @@ async def upsert( namespace: str, translation: translation_upsert_params.Translation, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, format: Literal["json", "po"] | Omit = omit, @@ -517,6 +551,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -549,6 +586,7 @@ async def upsert( "environment": environment, "namespace": namespace, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, "format": format, @@ -565,6 +603,7 @@ async def validate( *, environment: str, translation: translation_validate_params.Translation, + branch: 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, @@ -584,6 +623,9 @@ async def validate( translation: A translation object with a content attribute used to update or create a translation. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -605,7 +647,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, translation_validate_params.TranslationValidateParams + { + "environment": environment, + "branch": branch, + }, + translation_validate_params.TranslationValidateParams, ), ), cast_to=TranslationValidateResponse, diff --git a/src/knock_mapi/resources/variables.py b/src/knock_mapi/resources/variables.py index 8f542f1..72d2854 100644 --- a/src/knock_mapi/resources/variables.py +++ b/src/knock_mapi/resources/variables.py @@ -48,6 +48,7 @@ def list( environment: str, after: str | Omit = omit, before: str | Omit = omit, + branch: 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. @@ -66,6 +67,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + limit: The number of entries to fetch per-page. extra_headers: Send extra headers @@ -89,6 +93,7 @@ def list( "environment": environment, "after": after, "before": before, + "branch": branch, "limit": limit, }, variable_list_params.VariableListParams, @@ -124,6 +129,7 @@ def list( environment: str, after: str | Omit = omit, before: str | Omit = omit, + branch: 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. @@ -142,6 +148,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + limit: The number of entries to fetch per-page. extra_headers: Send extra headers @@ -165,6 +174,7 @@ def list( "environment": environment, "after": after, "before": before, + "branch": branch, "limit": limit, }, variable_list_params.VariableListParams, diff --git a/src/knock_mapi/resources/workflows/steps.py b/src/knock_mapi/resources/workflows/steps.py index f93ec3a..cdb25ed 100644 --- a/src/knock_mapi/resources/workflows/steps.py +++ b/src/knock_mapi/resources/workflows/steps.py @@ -50,6 +50,7 @@ def preview_template( workflow_key: str, environment: str, recipient: step_preview_template_params.Recipient, + branch: str | Omit = omit, actor: Optional[step_preview_template_params.Actor] | Omit = omit, data: Dict[str, object] | Omit = omit, tenant: Optional[str] | Omit = omit, @@ -69,6 +70,9 @@ def preview_template( recipient: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + actor: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. @@ -105,7 +109,11 @@ def preview_template( extra_body=extra_body, timeout=timeout, query=maybe_transform( - {"environment": environment}, step_preview_template_params.StepPreviewTemplateParams + { + "environment": environment, + "branch": branch, + }, + step_preview_template_params.StepPreviewTemplateParams, ), ), cast_to=StepPreviewTemplateResponse, @@ -139,6 +147,7 @@ async def preview_template( workflow_key: str, environment: str, recipient: step_preview_template_params.Recipient, + branch: str | Omit = omit, actor: Optional[step_preview_template_params.Actor] | Omit = omit, data: Dict[str, object] | Omit = omit, tenant: Optional[str] | Omit = omit, @@ -158,6 +167,9 @@ async def preview_template( recipient: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + actor: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. @@ -194,7 +206,11 @@ async def preview_template( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, step_preview_template_params.StepPreviewTemplateParams + { + "environment": environment, + "branch": branch, + }, + step_preview_template_params.StepPreviewTemplateParams, ), ), cast_to=StepPreviewTemplateResponse, diff --git a/src/knock_mapi/resources/workflows/workflows.py b/src/knock_mapi/resources/workflows/workflows.py index 98619a9..c42d4b5 100644 --- a/src/knock_mapi/resources/workflows/workflows.py +++ b/src/knock_mapi/resources/workflows/workflows.py @@ -74,6 +74,7 @@ def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -90,6 +91,9 @@ def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -114,6 +118,7 @@ def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, workflow_retrieve_params.WorkflowRetrieveParams, @@ -129,6 +134,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -152,6 +158,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -179,6 +188,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -194,6 +204,7 @@ def activate( *, environment: str, status: bool, + branch: 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, @@ -215,6 +226,9 @@ def activate( status: Whether to activate or deactivate the workflow. Set to `true` by default, which will activate the workflow. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -233,7 +247,13 @@ def activate( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, workflow_activate_params.WorkflowActivateParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + workflow_activate_params.WorkflowActivateParams, + ), ), cast_to=WorkflowActivateResponse, ) @@ -244,6 +264,7 @@ def run( *, environment: str, recipients: SequenceNotStr[workflow_run_params.Recipient], + branch: str | Omit = omit, actor: Optional[workflow_run_params.Actor] | Omit = omit, cancellation_key: Optional[str] | Omit = omit, data: Dict[str, object] | Omit = omit, @@ -264,6 +285,9 @@ def run( recipients: A list of recipients to run the workflow for. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + actor: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. @@ -300,7 +324,13 @@ def run( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, workflow_run_params.WorkflowRunParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + workflow_run_params.WorkflowRunParams, + ), ), cast_to=WorkflowRunResponse, ) @@ -312,6 +342,7 @@ def upsert( environment: str, workflow: workflow_upsert_params.Workflow, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -334,6 +365,9 @@ def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -360,6 +394,7 @@ def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -375,6 +410,7 @@ def validate( *, environment: str, workflow: workflow_validate_params.Workflow, + branch: 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, @@ -394,6 +430,9 @@ def validate( workflow: A workflow request for upserting a workflow. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -412,7 +451,13 @@ def validate( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=maybe_transform({"environment": environment}, workflow_validate_params.WorkflowValidateParams), + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + workflow_validate_params.WorkflowValidateParams, + ), ), cast_to=WorkflowValidateResponse, ) @@ -448,6 +493,7 @@ async def retrieve( *, environment: str, annotate: bool | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -464,6 +510,9 @@ async def retrieve( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -488,6 +537,7 @@ async def retrieve( { "environment": environment, "annotate": annotate, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, }, workflow_retrieve_params.WorkflowRetrieveParams, @@ -503,6 +553,7 @@ def list( after: str | Omit = omit, annotate: bool | Omit = omit, before: str | Omit = omit, + branch: str | Omit = omit, hide_uncommitted_changes: bool | 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. @@ -526,6 +577,9 @@ def list( before: The cursor to fetch entries before. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be returned. When false, both committed and uncommitted changes will be returned. @@ -553,6 +607,7 @@ def list( "after": after, "annotate": annotate, "before": before, + "branch": branch, "hide_uncommitted_changes": hide_uncommitted_changes, "limit": limit, }, @@ -568,6 +623,7 @@ async def activate( *, environment: str, status: bool, + branch: 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, @@ -589,6 +645,9 @@ async def activate( status: Whether to activate or deactivate the workflow. Set to `true` by default, which will activate the workflow. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -608,7 +667,11 @@ async def activate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, workflow_activate_params.WorkflowActivateParams + { + "environment": environment, + "branch": branch, + }, + workflow_activate_params.WorkflowActivateParams, ), ), cast_to=WorkflowActivateResponse, @@ -620,6 +683,7 @@ async def run( *, environment: str, recipients: SequenceNotStr[workflow_run_params.Recipient], + branch: str | Omit = omit, actor: Optional[workflow_run_params.Actor] | Omit = omit, cancellation_key: Optional[str] | Omit = omit, data: Dict[str, object] | Omit = omit, @@ -640,6 +704,9 @@ async def run( recipients: A list of recipients to run the workflow for. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + actor: A recipient reference, used when referencing a recipient by either their ID (for a user), or by a reference for an object. @@ -676,7 +743,13 @@ async def run( extra_query=extra_query, extra_body=extra_body, timeout=timeout, - query=await async_maybe_transform({"environment": environment}, workflow_run_params.WorkflowRunParams), + query=await async_maybe_transform( + { + "environment": environment, + "branch": branch, + }, + workflow_run_params.WorkflowRunParams, + ), ), cast_to=WorkflowRunResponse, ) @@ -688,6 +761,7 @@ async def upsert( environment: str, workflow: workflow_upsert_params.Workflow, annotate: bool | Omit = omit, + branch: str | Omit = omit, commit: bool | Omit = omit, commit_message: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -710,6 +784,9 @@ async def upsert( annotate: Whether to annotate the resource. Only used in the Knock CLI. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + commit: Whether to commit the resource at the same time as modifying it. commit_message: The message to commit the resource with, only used if `commit` is `true`. @@ -736,6 +813,7 @@ async def upsert( { "environment": environment, "annotate": annotate, + "branch": branch, "commit": commit, "commit_message": commit_message, }, @@ -751,6 +829,7 @@ async def validate( *, environment: str, workflow: workflow_validate_params.Workflow, + branch: 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, @@ -770,6 +849,9 @@ async def validate( workflow: A workflow request for upserting a workflow. + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -789,7 +871,11 @@ async def validate( extra_body=extra_body, timeout=timeout, query=await async_maybe_transform( - {"environment": environment}, workflow_validate_params.WorkflowValidateParams + { + "environment": environment, + "branch": branch, + }, + workflow_validate_params.WorkflowValidateParams, ), ), cast_to=WorkflowValidateResponse, diff --git a/src/knock_mapi/types/commit_commit_all_params.py b/src/knock_mapi/types/commit_commit_all_params.py index f723e02..c1f1f63 100644 --- a/src/knock_mapi/types/commit_commit_all_params.py +++ b/src/knock_mapi/types/commit_commit_all_params.py @@ -12,6 +12,12 @@ class CommitCommitAllParams(TypedDict, total=False): environment: Required[str] """The environment slug.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit_message: str """An optional message to include in a commit.""" diff --git a/src/knock_mapi/types/commit_list_params.py b/src/knock_mapi/types/commit_list_params.py index a9f2bce..ae8ada1 100644 --- a/src/knock_mapi/types/commit_list_params.py +++ b/src/knock_mapi/types/commit_list_params.py @@ -18,6 +18,12 @@ class CommitListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + limit: int """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/email_layout_list_params.py b/src/knock_mapi/types/email_layout_list_params.py index 8157a27..599130b 100644 --- a/src/knock_mapi/types/email_layout_list_params.py +++ b/src/knock_mapi/types/email_layout_list_params.py @@ -20,6 +20,12 @@ class EmailLayoutListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/email_layout_retrieve_params.py b/src/knock_mapi/types/email_layout_retrieve_params.py index df77534..77c421c 100644 --- a/src/knock_mapi/types/email_layout_retrieve_params.py +++ b/src/knock_mapi/types/email_layout_retrieve_params.py @@ -14,6 +14,12 @@ class EmailLayoutRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/email_layout_upsert_params.py b/src/knock_mapi/types/email_layout_upsert_params.py index b95f63d..2a02405 100644 --- a/src/knock_mapi/types/email_layout_upsert_params.py +++ b/src/knock_mapi/types/email_layout_upsert_params.py @@ -18,6 +18,12 @@ class EmailLayoutUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/email_layout_validate_params.py b/src/knock_mapi/types/email_layout_validate_params.py index 4a764cf..bf36504 100644 --- a/src/knock_mapi/types/email_layout_validate_params.py +++ b/src/knock_mapi/types/email_layout_validate_params.py @@ -15,6 +15,12 @@ class EmailLayoutValidateParams(TypedDict, total=False): email_layout: Required[EmailLayout] """A request to update or create an email layout.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class EmailLayoutFooterLink(TypedDict, total=False): text: Required[str] diff --git a/src/knock_mapi/types/guide_activate_params.py b/src/knock_mapi/types/guide_activate_params.py index 2c2e33e..e1692ec 100644 --- a/src/knock_mapi/types/guide_activate_params.py +++ b/src/knock_mapi/types/guide_activate_params.py @@ -18,11 +18,23 @@ class GuideBooleanActivationParams(TypedDict, total=False): status: Required[bool] """Whether to activate or deactivate the guide.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class GuideScheduledActivationParams(TypedDict, total=False): environment: Required[str] """The environment slug.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + from_: Annotated[Union[str, datetime], PropertyInfo(alias="from", format="iso8601")] """When to activate the guide. diff --git a/src/knock_mapi/types/guide_list_params.py b/src/knock_mapi/types/guide_list_params.py index ae4b83c..0f49fe4 100644 --- a/src/knock_mapi/types/guide_list_params.py +++ b/src/knock_mapi/types/guide_list_params.py @@ -20,6 +20,12 @@ class GuideListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/guide_retrieve_params.py b/src/knock_mapi/types/guide_retrieve_params.py index e012322..4f98219 100644 --- a/src/knock_mapi/types/guide_retrieve_params.py +++ b/src/knock_mapi/types/guide_retrieve_params.py @@ -14,6 +14,12 @@ class GuideRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index e2ec346..146661e 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -24,6 +24,12 @@ class GuideUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index 2c4edd4..aeaee81 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -21,6 +21,12 @@ class GuideValidateParams(TypedDict, total=False): guide: Required[Guide] """A request to create or update a guide.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class Guide(TypedDict, total=False): channel_key: Required[str] diff --git a/src/knock_mapi/types/message_type_list_params.py b/src/knock_mapi/types/message_type_list_params.py index 7207dbe..4f41323 100644 --- a/src/knock_mapi/types/message_type_list_params.py +++ b/src/knock_mapi/types/message_type_list_params.py @@ -20,6 +20,12 @@ class MessageTypeListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/message_type_retrieve_params.py b/src/knock_mapi/types/message_type_retrieve_params.py index 426be46..af59e6e 100644 --- a/src/knock_mapi/types/message_type_retrieve_params.py +++ b/src/knock_mapi/types/message_type_retrieve_params.py @@ -14,6 +14,12 @@ class MessageTypeRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/message_type_upsert_params.py b/src/knock_mapi/types/message_type_upsert_params.py index e8d98a5..4fbce07 100644 --- a/src/knock_mapi/types/message_type_upsert_params.py +++ b/src/knock_mapi/types/message_type_upsert_params.py @@ -20,6 +20,12 @@ class MessageTypeUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/message_type_validate_params.py b/src/knock_mapi/types/message_type_validate_params.py index 4b14a62..288a216 100644 --- a/src/knock_mapi/types/message_type_validate_params.py +++ b/src/knock_mapi/types/message_type_validate_params.py @@ -17,6 +17,12 @@ class MessageTypeValidateParams(TypedDict, total=False): message_type: Required[MessageType] """A request to create a message type.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class MessageType(TypedDict, total=False): description: Required[Optional[str]] diff --git a/src/knock_mapi/types/partial_list_params.py b/src/knock_mapi/types/partial_list_params.py index 1c19a18..41d5a9c 100644 --- a/src/knock_mapi/types/partial_list_params.py +++ b/src/knock_mapi/types/partial_list_params.py @@ -20,6 +20,12 @@ class PartialListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/partial_retrieve_params.py b/src/knock_mapi/types/partial_retrieve_params.py index 6b07e1e..31a6b0d 100644 --- a/src/knock_mapi/types/partial_retrieve_params.py +++ b/src/knock_mapi/types/partial_retrieve_params.py @@ -14,6 +14,12 @@ class PartialRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/partial_upsert_params.py b/src/knock_mapi/types/partial_upsert_params.py index a3c6609..b2a9993 100644 --- a/src/knock_mapi/types/partial_upsert_params.py +++ b/src/knock_mapi/types/partial_upsert_params.py @@ -18,6 +18,12 @@ class PartialUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/partial_validate_params.py b/src/knock_mapi/types/partial_validate_params.py index dde18a2..affc737 100644 --- a/src/knock_mapi/types/partial_validate_params.py +++ b/src/knock_mapi/types/partial_validate_params.py @@ -15,6 +15,12 @@ class PartialValidateParams(TypedDict, total=False): partial: Required[Partial] """A partial object with attributes to update or create a partial.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class Partial(TypedDict, total=False): content: Required[str] diff --git a/src/knock_mapi/types/translation_list_params.py b/src/knock_mapi/types/translation_list_params.py index b0d0876..17c55ad 100644 --- a/src/knock_mapi/types/translation_list_params.py +++ b/src/knock_mapi/types/translation_list_params.py @@ -20,6 +20,12 @@ class TranslationListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + format: Literal["json", "po"] """Optionally specify the returned content format. diff --git a/src/knock_mapi/types/translation_retrieve_params.py b/src/knock_mapi/types/translation_retrieve_params.py index 727ab24..3e00a62 100644 --- a/src/knock_mapi/types/translation_retrieve_params.py +++ b/src/knock_mapi/types/translation_retrieve_params.py @@ -14,6 +14,12 @@ class TranslationRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + format: Literal["json", "po"] """Optionally specify the returned content format. diff --git a/src/knock_mapi/types/translation_upsert_params.py b/src/knock_mapi/types/translation_upsert_params.py index a134c5d..fdd5dae 100644 --- a/src/knock_mapi/types/translation_upsert_params.py +++ b/src/knock_mapi/types/translation_upsert_params.py @@ -23,6 +23,12 @@ class TranslationUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/translation_validate_params.py b/src/knock_mapi/types/translation_validate_params.py index ed32ad9..f17e880 100644 --- a/src/knock_mapi/types/translation_validate_params.py +++ b/src/knock_mapi/types/translation_validate_params.py @@ -17,6 +17,12 @@ class TranslationValidateParams(TypedDict, total=False): translation. """ + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class Translation(TypedDict, total=False): content: Required[str] diff --git a/src/knock_mapi/types/variable_list_params.py b/src/knock_mapi/types/variable_list_params.py index 5f664e1..a8a438d 100644 --- a/src/knock_mapi/types/variable_list_params.py +++ b/src/knock_mapi/types/variable_list_params.py @@ -17,5 +17,11 @@ class VariableListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + limit: int """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/workflow_activate_params.py b/src/knock_mapi/types/workflow_activate_params.py index 5116fc2..157eb6e 100644 --- a/src/knock_mapi/types/workflow_activate_params.py +++ b/src/knock_mapi/types/workflow_activate_params.py @@ -16,3 +16,9 @@ class WorkflowActivateParams(TypedDict, total=False): Set to `true` by default, which will activate the workflow. """ + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ diff --git a/src/knock_mapi/types/workflow_list_params.py b/src/knock_mapi/types/workflow_list_params.py index bd5a380..b8f930a 100644 --- a/src/knock_mapi/types/workflow_list_params.py +++ b/src/knock_mapi/types/workflow_list_params.py @@ -20,6 +20,12 @@ class WorkflowListParams(TypedDict, total=False): before: str """The cursor to fetch entries before.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/workflow_retrieve_params.py b/src/knock_mapi/types/workflow_retrieve_params.py index 2398fb6..8f5c4df 100644 --- a/src/knock_mapi/types/workflow_retrieve_params.py +++ b/src/knock_mapi/types/workflow_retrieve_params.py @@ -14,6 +14,12 @@ class WorkflowRetrieveParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + hide_uncommitted_changes: bool """Whether to hide uncommitted changes. diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index ec3f357..0db1787 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -23,6 +23,12 @@ class WorkflowRunParams(TypedDict, total=False): recipients: Required[SequenceNotStr[Recipient]] """A list of recipients to run the workflow for.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + actor: Optional[Actor] """ A recipient reference, used when referencing a recipient by either their ID (for diff --git a/src/knock_mapi/types/workflow_upsert_params.py b/src/knock_mapi/types/workflow_upsert_params.py index e6316f6..2f1d86d 100644 --- a/src/knock_mapi/types/workflow_upsert_params.py +++ b/src/knock_mapi/types/workflow_upsert_params.py @@ -21,6 +21,12 @@ class WorkflowUpsertParams(TypedDict, total=False): annotate: bool """Whether to annotate the resource. Only used in the Knock CLI.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + commit: bool """Whether to commit the resource at the same time as modifying it.""" diff --git a/src/knock_mapi/types/workflow_validate_params.py b/src/knock_mapi/types/workflow_validate_params.py index 514b4ef..14d0ccc 100644 --- a/src/knock_mapi/types/workflow_validate_params.py +++ b/src/knock_mapi/types/workflow_validate_params.py @@ -18,6 +18,12 @@ class WorkflowValidateParams(TypedDict, total=False): workflow: Required[Workflow] """A workflow request for upserting a workflow.""" + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + class WorkflowSettings(TypedDict, total=False): is_commercial: bool diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index a688cc0..4f320f4 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -26,6 +26,12 @@ class StepPreviewTemplateParams(TypedDict, total=False): a user), or by a reference for an object. """ + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + actor: Optional[Actor] """ A recipient reference, used when referencing a recipient by either their ID (for diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index 1608b49..a5b7421 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -80,6 +80,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: environment="development", after="after", before="before", + branch="feature-branch", limit=0, promoted=True, resource_id="resource_id", @@ -126,6 +127,7 @@ def test_method_commit_all(self, client: KnockMgmt) -> None: def test_method_commit_all_with_all_params(self, client: KnockMgmt) -> None: commit = client.commits.commit_all( environment="development", + branch="feature-branch", commit_message="commit_message", resource_id="resource_id", resource_type="audience", @@ -307,6 +309,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - environment="development", after="after", before="before", + branch="feature-branch", limit=0, promoted=True, resource_id="resource_id", @@ -353,6 +356,7 @@ async def test_method_commit_all(self, async_client: AsyncKnockMgmt) -> None: async def test_method_commit_all_with_all_params(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.commit_all( environment="development", + branch="feature-branch", commit_message="commit_message", resource_id="resource_id", resource_type="audience", diff --git a/tests/api_resources/test_email_layouts.py b/tests/api_resources/test_email_layouts.py index ab47629..46e772d 100644 --- a/tests/api_resources/test_email_layouts.py +++ b/tests/api_resources/test_email_layouts.py @@ -38,6 +38,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: email_layout_key="email_layout_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(EmailLayout, email_layout, path=["response"]) @@ -95,6 +96,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -158,6 +160,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ], }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -246,6 +249,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: } ], }, + branch="feature-branch", ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) @@ -323,6 +327,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm email_layout_key="email_layout_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(EmailLayout, email_layout, path=["response"]) @@ -380,6 +385,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -443,6 +449,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ], }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -531,6 +538,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm } ], }, + branch="feature-branch", ) assert_matches_type(EmailLayoutValidateResponse, email_layout, path=["response"]) diff --git a/tests/api_resources/test_guides.py b/tests/api_resources/test_guides.py index ccb8624..1044e06 100644 --- a/tests/api_resources/test_guides.py +++ b/tests/api_resources/test_guides.py @@ -41,6 +41,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: guide_key="guide_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(Guide, guide, path=["response"]) @@ -98,6 +99,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -139,6 +141,17 @@ def test_method_activate_overload_1(self, client: KnockMgmt) -> None: ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_activate_with_all_params_overload_1(self, client: KnockMgmt) -> None: + guide = client.guides.activate( + guide_key="guide_key", + environment="development", + status=True, + branch="feature-branch", + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_activate_overload_1(self, client: KnockMgmt) -> None: @@ -194,6 +207,7 @@ def test_method_activate_with_all_params_overload_2(self, client: KnockMgmt) -> guide = client.guides.activate( guide_key="guide_key", environment="development", + branch="feature-branch", from_=parse_datetime("2024-03-20T10:00:00Z"), until=parse_datetime("2024-03-21T10:00:00Z"), ) @@ -339,6 +353,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: }, }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -477,6 +492,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: ] }, }, + branch="feature-branch", ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) @@ -575,6 +591,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm guide_key="guide_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(Guide, guide, path=["response"]) @@ -632,6 +649,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -673,6 +691,17 @@ async def test_method_activate_overload_1(self, async_client: AsyncKnockMgmt) -> ) assert_matches_type(GuideActivateResponse, guide, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_activate_with_all_params_overload_1(self, async_client: AsyncKnockMgmt) -> None: + guide = await async_client.guides.activate( + guide_key="guide_key", + environment="development", + status=True, + branch="feature-branch", + ) + assert_matches_type(GuideActivateResponse, guide, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_activate_overload_1(self, async_client: AsyncKnockMgmt) -> None: @@ -728,6 +757,7 @@ async def test_method_activate_with_all_params_overload_2(self, async_client: As guide = await async_client.guides.activate( guide_key="guide_key", environment="development", + branch="feature-branch", from_=parse_datetime("2024-03-20T10:00:00Z"), until=parse_datetime("2024-03-21T10:00:00Z"), ) @@ -873,6 +903,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) }, }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -1011,6 +1042,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm ] }, }, + branch="feature-branch", ) assert_matches_type(GuideValidateResponse, guide, path=["response"]) diff --git a/tests/api_resources/test_message_types.py b/tests/api_resources/test_message_types.py index 7cf1bbd..d9a583c 100644 --- a/tests/api_resources/test_message_types.py +++ b/tests/api_resources/test_message_types.py @@ -38,6 +38,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: message_type_key="email", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(MessageType, message_type, path=["response"]) @@ -95,6 +96,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -174,6 +176,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: ], }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -278,6 +281,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: } ], }, + branch="feature-branch", ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) @@ -355,6 +359,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm message_type_key="email", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(MessageType, message_type, path=["response"]) @@ -412,6 +417,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -491,6 +497,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) ], }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -595,6 +602,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm } ], }, + branch="feature-branch", ) assert_matches_type(MessageTypeValidateResponse, message_type, path=["response"]) diff --git a/tests/api_resources/test_partials.py b/tests/api_resources/test_partials.py index 230aeea..6890b37 100644 --- a/tests/api_resources/test_partials.py +++ b/tests/api_resources/test_partials.py @@ -38,6 +38,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: partial_key="partial_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(Partial, partial, path=["response"]) @@ -95,6 +96,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -155,6 +157,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "visual_block_enabled": False, }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -240,6 +243,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "icon_name": "icon_name", "visual_block_enabled": False, }, + branch="feature-branch", ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) @@ -317,6 +321,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm partial_key="partial_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(Partial, partial, path=["response"]) @@ -374,6 +379,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -434,6 +440,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "visual_block_enabled": False, }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -519,6 +526,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "icon_name": "icon_name", "visual_block_enabled": False, }, + branch="feature-branch", ) assert_matches_type(PartialValidateResponse, partial, path=["response"]) diff --git a/tests/api_resources/test_translations.py b/tests/api_resources/test_translations.py index 51782ce..c3f712a 100644 --- a/tests/api_resources/test_translations.py +++ b/tests/api_resources/test_translations.py @@ -39,6 +39,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: locale_code="locale_code", environment="development", annotate=True, + branch="feature-branch", format="json", hide_uncommitted_changes=True, namespace="namespace", @@ -98,6 +99,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", format="json", hide_uncommitted_changes=True, limit=0, @@ -158,6 +160,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "format": "json", }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", format="json", @@ -229,6 +232,20 @@ def test_method_validate(self, client: KnockMgmt) -> None: ) assert_matches_type(TranslationValidateResponse, translation, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: + translation = client.translations.validate( + locale_code="locale_code", + environment="development", + translation={ + "content": '{"hello":"Hello, world!"}', + "format": "json", + }, + branch="feature-branch", + ) + assert_matches_type(TranslationValidateResponse, translation, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_validate(self, client: KnockMgmt) -> None: @@ -300,6 +317,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm locale_code="locale_code", environment="development", annotate=True, + branch="feature-branch", format="json", hide_uncommitted_changes=True, namespace="namespace", @@ -359,6 +377,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", format="json", hide_uncommitted_changes=True, limit=0, @@ -419,6 +438,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "format": "json", }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", format="json", @@ -490,6 +510,20 @@ async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(TranslationValidateResponse, translation, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + translation = await async_client.translations.validate( + locale_code="locale_code", + environment="development", + translation={ + "content": '{"hello":"Hello, world!"}', + "format": "json", + }, + branch="feature-branch", + ) + assert_matches_type(TranslationValidateResponse, translation, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: diff --git a/tests/api_resources/test_variables.py b/tests/api_resources/test_variables.py index 2e8b340..51d3646 100644 --- a/tests/api_resources/test_variables.py +++ b/tests/api_resources/test_variables.py @@ -33,6 +33,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: environment="development", after="after", before="before", + branch="feature-branch", limit=0, ) assert_matches_type(SyncEntriesCursor[Variable], variable, path=["response"]) @@ -84,6 +85,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - environment="development", after="after", before="before", + branch="feature-branch", limit=0, ) assert_matches_type(AsyncEntriesCursor[Variable], variable, path=["response"]) diff --git a/tests/api_resources/test_workflows.py b/tests/api_resources/test_workflows.py index 6a7954f..8f57aae 100644 --- a/tests/api_resources/test_workflows.py +++ b/tests/api_resources/test_workflows.py @@ -41,6 +41,7 @@ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: workflow_key="workflow_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @@ -98,6 +99,7 @@ def test_method_list_with_all_params(self, client: KnockMgmt) -> None: after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -139,6 +141,17 @@ def test_method_activate(self, client: KnockMgmt) -> None: ) assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_activate_with_all_params(self, client: KnockMgmt) -> None: + workflow = client.workflows.activate( + workflow_key="workflow_key", + environment="development", + status=True, + branch="feature-branch", + ) + assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize def test_raw_response_activate(self, client: KnockMgmt) -> None: @@ -196,6 +209,7 @@ def test_method_run_with_all_params(self, client: KnockMgmt) -> None: workflow_key="workflow_key", environment="development", recipients=["dnedry"], + branch="feature-branch", actor={ "id": "project_1", "collection": "projects", @@ -331,6 +345,7 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: "trigger_frequency": "every_trigger", }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -487,6 +502,7 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: "trigger_data_json_schema": {"foo": "bar"}, "trigger_frequency": "every_trigger", }, + branch="feature-branch", ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) @@ -579,6 +595,7 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgm workflow_key="workflow_key", environment="development", annotate=True, + branch="feature-branch", hide_uncommitted_changes=True, ) assert_matches_type(WorkflowRetrieveResponse, workflow, path=["response"]) @@ -636,6 +653,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) - after="after", annotate=True, before="before", + branch="feature-branch", hide_uncommitted_changes=True, limit=0, ) @@ -677,6 +695,17 @@ async def test_method_activate(self, async_client: AsyncKnockMgmt) -> None: ) assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_activate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + workflow = await async_client.workflows.activate( + workflow_key="workflow_key", + environment="development", + status=True, + branch="feature-branch", + ) + assert_matches_type(WorkflowActivateResponse, workflow, path=["response"]) + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") @parametrize async def test_raw_response_activate(self, async_client: AsyncKnockMgmt) -> None: @@ -734,6 +763,7 @@ async def test_method_run_with_all_params(self, async_client: AsyncKnockMgmt) -> workflow_key="workflow_key", environment="development", recipients=["dnedry"], + branch="feature-branch", actor={ "id": "project_1", "collection": "projects", @@ -869,6 +899,7 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) "trigger_frequency": "every_trigger", }, annotate=True, + branch="feature-branch", commit=True, commit_message="commit_message", ) @@ -1025,6 +1056,7 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm "trigger_data_json_schema": {"foo": "bar"}, "trigger_frequency": "every_trigger", }, + branch="feature-branch", ) assert_matches_type(WorkflowValidateResponse, workflow, path=["response"]) diff --git a/tests/api_resources/workflows/test_steps.py b/tests/api_resources/workflows/test_steps.py index 74f54ed..4adb797 100644 --- a/tests/api_resources/workflows/test_steps.py +++ b/tests/api_resources/workflows/test_steps.py @@ -36,6 +36,7 @@ def test_method_preview_template_with_all_params(self, client: KnockMgmt) -> Non workflow_key="workflow_key", environment="development", recipient="dnedry", + branch="feature-branch", actor="dnedry", data={"park_id": "bar"}, tenant="acme-corp", @@ -118,6 +119,7 @@ async def test_method_preview_template_with_all_params(self, async_client: Async workflow_key="workflow_key", environment="development", recipient="dnedry", + branch="feature-branch", actor="dnedry", data={"park_id": "bar"}, tenant="acme-corp", From 070beab81747bc7eac7426c124b29b710cb21b07 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:40:20 +0000 Subject: [PATCH 087/101] feat(api): manual updates --- .stats.yml | 4 +- api.md | 15 + src/knock_mapi/_client.py | 9 + src/knock_mapi/resources/__init__.py | 14 + src/knock_mapi/resources/branches.py | 498 ++++++++++++++++++ src/knock_mapi/types/__init__.py | 5 + src/knock_mapi/types/branch.py | 25 + src/knock_mapi/types/branch_create_params.py | 12 + src/knock_mapi/types/branch_delete_params.py | 12 + src/knock_mapi/types/branch_list_params.py | 21 + .../types/branch_retrieve_params.py | 12 + tests/api_resources/test_branches.py | 393 ++++++++++++++ 12 files changed, 1018 insertions(+), 2 deletions(-) create mode 100644 src/knock_mapi/resources/branches.py create mode 100644 src/knock_mapi/types/branch.py create mode 100644 src/knock_mapi/types/branch_create_params.py create mode 100644 src/knock_mapi/types/branch_delete_params.py create mode 100644 src/knock_mapi/types/branch_list_params.py create mode 100644 src/knock_mapi/types/branch_retrieve_params.py create mode 100644 tests/api_resources/test_branches.py diff --git a/.stats.yml b/.stats.yml index f2bcb18..8c14229 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 41 +configured_endpoints: 45 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-310a2e25c41149fe061e3c53d969392ca8bf4335762a32ce5b5d376990f4037d.yml openapi_spec_hash: 0399fa6824e38cdb61fc9e8bd55d9622 -config_hash: 643ed3f0dab73b4c79c1657cc34ef298 +config_hash: 34780c6a4340e5f9ddfb18f6b534eea5 diff --git a/api.md b/api.md index c1a8542..c194a69 100644 --- a/api.md +++ b/api.md @@ -269,3 +269,18 @@ Methods: - client.guides.archive(guide_key) -> GuideArchiveResponse - client.guides.upsert(guide_key, \*\*params) -> GuideUpsertResponse - client.guides.validate(guide_key, \*\*params) -> GuideValidateResponse + +# Branches + +Types: + +```python +from knock_mapi.types import Branch +``` + +Methods: + +- client.branches.create(branch_slug, \*\*params) -> Branch +- client.branches.retrieve(branch_slug, \*\*params) -> Branch +- client.branches.list(\*\*params) -> SyncEntriesCursor[Branch] +- client.branches.delete(branch_slug, \*\*params) -> None diff --git a/src/knock_mapi/_client.py b/src/knock_mapi/_client.py index 716d891..b49d2ae 100644 --- a/src/knock_mapi/_client.py +++ b/src/knock_mapi/_client.py @@ -26,6 +26,7 @@ guides, commits, api_keys, + branches, channels, partials, variables, @@ -70,6 +71,7 @@ class KnockMgmt(SyncAPIClient): environments: environments.EnvironmentsResource variables: variables.VariablesResource guides: guides.GuidesResource + branches: branches.BranchesResource with_raw_response: KnockMgmtWithRawResponse with_streaming_response: KnockMgmtWithStreamedResponse @@ -140,6 +142,7 @@ def __init__( self.environments = environments.EnvironmentsResource(self) self.variables = variables.VariablesResource(self) self.guides = guides.GuidesResource(self) + self.branches = branches.BranchesResource(self) self.with_raw_response = KnockMgmtWithRawResponse(self) self.with_streaming_response = KnockMgmtWithStreamedResponse(self) @@ -262,6 +265,7 @@ class AsyncKnockMgmt(AsyncAPIClient): environments: environments.AsyncEnvironmentsResource variables: variables.AsyncVariablesResource guides: guides.AsyncGuidesResource + branches: branches.AsyncBranchesResource with_raw_response: AsyncKnockMgmtWithRawResponse with_streaming_response: AsyncKnockMgmtWithStreamedResponse @@ -332,6 +336,7 @@ def __init__( self.environments = environments.AsyncEnvironmentsResource(self) self.variables = variables.AsyncVariablesResource(self) self.guides = guides.AsyncGuidesResource(self) + self.branches = branches.AsyncBranchesResource(self) self.with_raw_response = AsyncKnockMgmtWithRawResponse(self) self.with_streaming_response = AsyncKnockMgmtWithStreamedResponse(self) @@ -455,6 +460,7 @@ def __init__(self, client: KnockMgmt) -> None: self.environments = environments.EnvironmentsResourceWithRawResponse(client.environments) self.variables = variables.VariablesResourceWithRawResponse(client.variables) self.guides = guides.GuidesResourceWithRawResponse(client.guides) + self.branches = branches.BranchesResourceWithRawResponse(client.branches) class AsyncKnockMgmtWithRawResponse: @@ -472,6 +478,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.environments = environments.AsyncEnvironmentsResourceWithRawResponse(client.environments) self.variables = variables.AsyncVariablesResourceWithRawResponse(client.variables) self.guides = guides.AsyncGuidesResourceWithRawResponse(client.guides) + self.branches = branches.AsyncBranchesResourceWithRawResponse(client.branches) class KnockMgmtWithStreamedResponse: @@ -489,6 +496,7 @@ def __init__(self, client: KnockMgmt) -> None: self.environments = environments.EnvironmentsResourceWithStreamingResponse(client.environments) self.variables = variables.VariablesResourceWithStreamingResponse(client.variables) self.guides = guides.GuidesResourceWithStreamingResponse(client.guides) + self.branches = branches.BranchesResourceWithStreamingResponse(client.branches) class AsyncKnockMgmtWithStreamedResponse: @@ -506,6 +514,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.environments = environments.AsyncEnvironmentsResourceWithStreamingResponse(client.environments) self.variables = variables.AsyncVariablesResourceWithStreamingResponse(client.variables) self.guides = guides.AsyncGuidesResourceWithStreamingResponse(client.guides) + self.branches = branches.AsyncBranchesResourceWithStreamingResponse(client.branches) Client = KnockMgmt diff --git a/src/knock_mapi/resources/__init__.py b/src/knock_mapi/resources/__init__.py index e1e8da3..a95769c 100644 --- a/src/knock_mapi/resources/__init__.py +++ b/src/knock_mapi/resources/__init__.py @@ -32,6 +32,14 @@ APIKeysResourceWithStreamingResponse, AsyncAPIKeysResourceWithStreamingResponse, ) +from .branches import ( + BranchesResource, + AsyncBranchesResource, + BranchesResourceWithRawResponse, + AsyncBranchesResourceWithRawResponse, + BranchesResourceWithStreamingResponse, + AsyncBranchesResourceWithStreamingResponse, +) from .channels import ( ChannelsResource, AsyncChannelsResource, @@ -184,4 +192,10 @@ "AsyncGuidesResourceWithRawResponse", "GuidesResourceWithStreamingResponse", "AsyncGuidesResourceWithStreamingResponse", + "BranchesResource", + "AsyncBranchesResource", + "BranchesResourceWithRawResponse", + "AsyncBranchesResourceWithRawResponse", + "BranchesResourceWithStreamingResponse", + "AsyncBranchesResourceWithStreamingResponse", ] diff --git a/src/knock_mapi/resources/branches.py b/src/knock_mapi/resources/branches.py new file mode 100644 index 0000000..fc7b5c5 --- /dev/null +++ b/src/knock_mapi/resources/branches.py @@ -0,0 +1,498 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..types import branch_list_params, branch_create_params, branch_delete_params, branch_retrieve_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 ..pagination import SyncEntriesCursor, AsyncEntriesCursor +from .._base_client import AsyncPaginator, make_request_options +from ..types.branch import Branch + +__all__ = ["BranchesResource", "AsyncBranchesResource"] + + +class BranchesResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BranchesResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return BranchesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BranchesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return BranchesResourceWithStreamingResponse(self) + + def create( + self, + branch_slug: str, + *, + environment: 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, + ) -> Branch: + """ + Creates a new branch off of the development environment with the given slug. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + return self._post( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"environment": environment}, branch_create_params.BranchCreateParams), + ), + cast_to=Branch, + ) + + def retrieve( + self, + branch_slug: str, + *, + environment: 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, + ) -> Branch: + """ + Returns a single branch by the `branch_slug`. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + return self._get( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"environment": environment}, branch_retrieve_params.BranchRetrieveParams), + ), + cast_to=Branch, + ) + + def list( + self, + *, + environment: str, + after: str | Omit = omit, + before: 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, + ) -> SyncEntriesCursor[Branch]: + """Returns a paginated list of branches. + + The branches will be returned in order of + their last commit time (newest first). + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + before: The cursor to fetch entries before. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/branches", + page=SyncEntriesCursor[Branch], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "before": before, + "limit": limit, + }, + branch_list_params.BranchListParams, + ), + ), + model=Branch, + ) + + def delete( + self, + branch_slug: str, + *, + environment: 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: + """ + Deletes a branch by the `branch_slug`. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"environment": environment}, branch_delete_params.BranchDeleteParams), + ), + cast_to=NoneType, + ) + + +class AsyncBranchesResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBranchesResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return AsyncBranchesResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBranchesResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return AsyncBranchesResourceWithStreamingResponse(self) + + async def create( + self, + branch_slug: str, + *, + environment: 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, + ) -> Branch: + """ + Creates a new branch off of the development environment with the given slug. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + return await self._post( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"environment": environment}, branch_create_params.BranchCreateParams + ), + ), + cast_to=Branch, + ) + + async def retrieve( + self, + branch_slug: str, + *, + environment: 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, + ) -> Branch: + """ + Returns a single branch by the `branch_slug`. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + return await self._get( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"environment": environment}, branch_retrieve_params.BranchRetrieveParams + ), + ), + cast_to=Branch, + ) + + def list( + self, + *, + environment: str, + after: str | Omit = omit, + before: 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[Branch, AsyncEntriesCursor[Branch]]: + """Returns a paginated list of branches. + + The branches will be returned in order of + their last commit time (newest first). + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + before: The cursor to fetch entries before. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/branches", + page=AsyncEntriesCursor[Branch], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "before": before, + "limit": limit, + }, + branch_list_params.BranchListParams, + ), + ), + model=Branch, + ) + + async def delete( + self, + branch_slug: str, + *, + environment: 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: + """ + Deletes a branch by the `branch_slug`. + + Args: + environment: The environment slug. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 branch_slug: + raise ValueError(f"Expected a non-empty value for `branch_slug` but received {branch_slug!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/v1/branches/{branch_slug}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"environment": environment}, branch_delete_params.BranchDeleteParams + ), + ), + cast_to=NoneType, + ) + + +class BranchesResourceWithRawResponse: + def __init__(self, branches: BranchesResource) -> None: + self._branches = branches + + self.create = to_raw_response_wrapper( + branches.create, + ) + self.retrieve = to_raw_response_wrapper( + branches.retrieve, + ) + self.list = to_raw_response_wrapper( + branches.list, + ) + self.delete = to_raw_response_wrapper( + branches.delete, + ) + + +class AsyncBranchesResourceWithRawResponse: + def __init__(self, branches: AsyncBranchesResource) -> None: + self._branches = branches + + self.create = async_to_raw_response_wrapper( + branches.create, + ) + self.retrieve = async_to_raw_response_wrapper( + branches.retrieve, + ) + self.list = async_to_raw_response_wrapper( + branches.list, + ) + self.delete = async_to_raw_response_wrapper( + branches.delete, + ) + + +class BranchesResourceWithStreamingResponse: + def __init__(self, branches: BranchesResource) -> None: + self._branches = branches + + self.create = to_streamed_response_wrapper( + branches.create, + ) + self.retrieve = to_streamed_response_wrapper( + branches.retrieve, + ) + self.list = to_streamed_response_wrapper( + branches.list, + ) + self.delete = to_streamed_response_wrapper( + branches.delete, + ) + + +class AsyncBranchesResourceWithStreamingResponse: + def __init__(self, branches: AsyncBranchesResource) -> None: + self._branches = branches + + self.create = async_to_streamed_response_wrapper( + branches.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + branches.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + branches.list, + ) + self.delete = async_to_streamed_response_wrapper( + branches.delete, + ) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index 04cfd48..e053a79 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -12,6 +12,7 @@ ) from .. import _compat from .guide import Guide as Guide +from .branch import Branch as Branch from .commit import Commit as Commit from .shared import PageInfo as PageInfo from .channel import Channel as Channel @@ -41,6 +42,7 @@ from .guide_list_params import GuideListParams as GuideListParams from .send_window_param import SendWindowParam as SendWindowParam from .workflow_sms_step import WorkflowSMSStep as WorkflowSMSStep +from .branch_list_params import BranchListParams as BranchListParams from .channel_group_rule import ChannelGroupRule as ChannelGroupRule from .commit_list_params import CommitListParams as CommitListParams from .sms_template_param import SMSTemplateParam as SMSTemplateParam @@ -58,6 +60,8 @@ from .workflow_run_params import WorkflowRunParams as WorkflowRunParams from .workflow_step_param import WorkflowStepParam as WorkflowStepParam from .auth_verify_response import AuthVerifyResponse as AuthVerifyResponse +from .branch_create_params import BranchCreateParams as BranchCreateParams +from .branch_delete_params import BranchDeleteParams as BranchDeleteParams from .email_template_param import EmailTemplateParam as EmailTemplateParam from .in_app_feed_template import InAppFeedTemplate as InAppFeedTemplate from .message_type_variant import MessageTypeVariant as MessageTypeVariant @@ -75,6 +79,7 @@ from .push_channel_settings import PushChannelSettings as PushChannelSettings from .workflow_run_response import WorkflowRunResponse as WorkflowRunResponse from .workflow_webhook_step import WorkflowWebhookStep as WorkflowWebhookStep +from .branch_retrieve_params import BranchRetrieveParams as BranchRetrieveParams from .email_channel_settings import EmailChannelSettings as EmailChannelSettings from .guide_archive_response import GuideArchiveResponse as GuideArchiveResponse from .request_template_param import RequestTemplateParam as RequestTemplateParam diff --git a/src/knock_mapi/types/branch.py b/src/knock_mapi/types/branch.py new file mode 100644 index 0000000..2131be1 --- /dev/null +++ b/src/knock_mapi/types/branch.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["Branch"] + + +class Branch(BaseModel): + created_at: datetime + """The timestamp of when the branch was created.""" + + slug: str + """A unique slug for the branch. Cannot exceed 255 characters.""" + + updated_at: datetime + """The timestamp of when the branch was last updated.""" + + deleted_at: Optional[datetime] = None + """The timestamp of when the branch was deleted.""" + + last_commit_at: Optional[datetime] = None + """The timestamp of the most-recent commit in the branch.""" diff --git a/src/knock_mapi/types/branch_create_params.py b/src/knock_mapi/types/branch_create_params.py new file mode 100644 index 0000000..2277bdb --- /dev/null +++ b/src/knock_mapi/types/branch_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BranchCreateParams"] + + +class BranchCreateParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" diff --git a/src/knock_mapi/types/branch_delete_params.py b/src/knock_mapi/types/branch_delete_params.py new file mode 100644 index 0000000..6b5b601 --- /dev/null +++ b/src/knock_mapi/types/branch_delete_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BranchDeleteParams"] + + +class BranchDeleteParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" diff --git a/src/knock_mapi/types/branch_list_params.py b/src/knock_mapi/types/branch_list_params.py new file mode 100644 index 0000000..b5d0fd1 --- /dev/null +++ b/src/knock_mapi/types/branch_list_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BranchListParams"] + + +class BranchListParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + after: str + """The cursor to fetch entries after.""" + + before: str + """The cursor to fetch entries before.""" + + limit: int + """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/branch_retrieve_params.py b/src/knock_mapi/types/branch_retrieve_params.py new file mode 100644 index 0000000..e0a98e5 --- /dev/null +++ b/src/knock_mapi/types/branch_retrieve_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BranchRetrieveParams"] + + +class BranchRetrieveParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" diff --git a/tests/api_resources/test_branches.py b/tests/api_resources/test_branches.py new file mode 100644 index 0000000..4ce2474 --- /dev/null +++ b/tests/api_resources/test_branches.py @@ -0,0 +1,393 @@ +# 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 knock_mapi import KnockMgmt, AsyncKnockMgmt +from tests.utils import assert_matches_type +from knock_mapi.types import ( + Branch, +) +from knock_mapi.pagination import SyncEntriesCursor, AsyncEntriesCursor + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBranches: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_create(self, client: KnockMgmt) -> None: + branch = client.branches.create( + branch_slug="feature-branch", + environment="development", + ) + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_create(self, client: KnockMgmt) -> None: + response = client.branches.with_raw_response.create( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_create(self, client: KnockMgmt) -> None: + with client.branches.with_streaming_response.create( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_create(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + client.branches.with_raw_response.create( + branch_slug="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_retrieve(self, client: KnockMgmt) -> None: + branch = client.branches.retrieve( + branch_slug="feature-branch", + environment="development", + ) + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_retrieve(self, client: KnockMgmt) -> None: + response = client.branches.with_raw_response.retrieve( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: + with client.branches.with_streaming_response.retrieve( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_retrieve(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + client.branches.with_raw_response.retrieve( + branch_slug="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_list(self, client: KnockMgmt) -> None: + branch = client.branches.list( + environment="development", + ) + assert_matches_type(SyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_list_with_all_params(self, client: KnockMgmt) -> None: + branch = client.branches.list( + environment="development", + after="after", + before="before", + limit=0, + ) + assert_matches_type(SyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_list(self, client: KnockMgmt) -> None: + response = client.branches.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = response.parse() + assert_matches_type(SyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_list(self, client: KnockMgmt) -> None: + with client.branches.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = response.parse() + assert_matches_type(SyncEntriesCursor[Branch], branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_delete(self, client: KnockMgmt) -> None: + branch = client.branches.delete( + branch_slug="feature-branch", + environment="development", + ) + assert branch is None + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_delete(self, client: KnockMgmt) -> None: + response = client.branches.with_raw_response.delete( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = response.parse() + assert branch is None + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_delete(self, client: KnockMgmt) -> None: + with client.branches.with_streaming_response.delete( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = response.parse() + assert branch is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_delete(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + client.branches.with_raw_response.delete( + branch_slug="", + environment="development", + ) + + +class TestAsyncBranches: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_create(self, async_client: AsyncKnockMgmt) -> None: + branch = await async_client.branches.create( + branch_slug="feature-branch", + environment="development", + ) + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_create(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.branches.with_raw_response.create( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = await response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.branches.with_streaming_response.create( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = await response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_create(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + await async_client.branches.with_raw_response.create( + branch_slug="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: + branch = await async_client.branches.retrieve( + branch_slug="feature-branch", + environment="development", + ) + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.branches.with_raw_response.retrieve( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = await response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.branches.with_streaming_response.retrieve( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = await response.parse() + assert_matches_type(Branch, branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + await async_client.branches.with_raw_response.retrieve( + branch_slug="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: + branch = await async_client.branches.list( + environment="development", + ) + assert_matches_type(AsyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + branch = await async_client.branches.list( + environment="development", + after="after", + before="before", + limit=0, + ) + assert_matches_type(AsyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.branches.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = await response.parse() + assert_matches_type(AsyncEntriesCursor[Branch], branch, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.branches.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = await response.parse() + assert_matches_type(AsyncEntriesCursor[Branch], branch, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_delete(self, async_client: AsyncKnockMgmt) -> None: + branch = await async_client.branches.delete( + branch_slug="feature-branch", + environment="development", + ) + assert branch is None + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.branches.with_raw_response.delete( + branch_slug="feature-branch", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + branch = await response.parse() + assert branch is None + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.branches.with_streaming_response.delete( + branch_slug="feature-branch", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + branch = await response.parse() + assert branch is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_delete(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `branch_slug` but received ''"): + await async_client.branches.with_raw_response.delete( + branch_slug="", + environment="development", + ) From 6b36373b2cad5c9cccf12a10f8c257b6e97bceae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:49:31 +0000 Subject: [PATCH 088/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/resources/commits.py | 14 ++++++++++++-- src/knock_mapi/types/commit_promote_all_params.py | 6 +++++- tests/api_resources/test_commits.py | 2 ++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8c14229..c971f40 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 45 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-310a2e25c41149fe061e3c53d969392ca8bf4335762a32ce5b5d376990f4037d.yml -openapi_spec_hash: 0399fa6824e38cdb61fc9e8bd55d9622 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-3ecceed264a62adba59c787f105549f62109739328db523366159f22c2ed1ee6.yml +openapi_spec_hash: 80b5362bf4f1ce98bc016406dc7e1bed config_hash: 34780c6a4340e5f9ddfb18f6b534eea5 diff --git a/src/knock_mapi/resources/commits.py b/src/knock_mapi/resources/commits.py index cb97fc9..ffbfad4 100644 --- a/src/knock_mapi/resources/commits.py +++ b/src/knock_mapi/resources/commits.py @@ -233,6 +233,7 @@ def promote_all( self, *, to_environment: str, + branch: str | Omit = omit, resource_id: str | Omit = omit, resource_type: Union[ Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], @@ -258,7 +259,10 @@ def promote_all( “production” (in that order), setting this param to “production” will promote all commits not currently in production from staging. - Note: This must be a non-development environment. + When this param is set to `"development"`, the `"branch"` param must be + provided. + + branch: The slug of the branch to promote all changes from. resource_id: Filter commits to promote by resource identifier. Must be used together with resource_type. @@ -284,6 +288,7 @@ def promote_all( query=maybe_transform( { "to_environment": to_environment, + "branch": branch, "resource_id": resource_id, "resource_type": resource_type, }, @@ -532,6 +537,7 @@ async def promote_all( self, *, to_environment: str, + branch: str | Omit = omit, resource_id: str | Omit = omit, resource_type: Union[ Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"], @@ -557,7 +563,10 @@ async def promote_all( “production” (in that order), setting this param to “production” will promote all commits not currently in production from staging. - Note: This must be a non-development environment. + When this param is set to `"development"`, the `"branch"` param must be + provided. + + branch: The slug of the branch to promote all changes from. resource_id: Filter commits to promote by resource identifier. Must be used together with resource_type. @@ -583,6 +592,7 @@ async def promote_all( query=await async_maybe_transform( { "to_environment": to_environment, + "branch": branch, "resource_id": resource_id, "resource_type": resource_type, }, diff --git a/src/knock_mapi/types/commit_promote_all_params.py b/src/knock_mapi/types/commit_promote_all_params.py index 1309013..3cb5201 100644 --- a/src/knock_mapi/types/commit_promote_all_params.py +++ b/src/knock_mapi/types/commit_promote_all_params.py @@ -18,9 +18,13 @@ class CommitPromoteAllParams(TypedDict, total=False): “production” (in that order), setting this param to “production” will promote all commits not currently in production from staging. - Note: This must be a non-development environment. + When this param is set to `"development"`, the `"branch"` param must be + provided. """ + branch: str + """The slug of the branch to promote all changes from.""" + resource_id: str """Filter commits to promote by resource identifier. diff --git a/tests/api_resources/test_commits.py b/tests/api_resources/test_commits.py index a5b7421..00544c7 100644 --- a/tests/api_resources/test_commits.py +++ b/tests/api_resources/test_commits.py @@ -173,6 +173,7 @@ def test_method_promote_all(self, client: KnockMgmt) -> None: def test_method_promote_all_with_all_params(self, client: KnockMgmt) -> None: commit = client.commits.promote_all( to_environment="to_environment", + branch="branch", resource_id="resource_id", resource_type="audience", ) @@ -402,6 +403,7 @@ async def test_method_promote_all(self, async_client: AsyncKnockMgmt) -> None: async def test_method_promote_all_with_all_params(self, async_client: AsyncKnockMgmt) -> None: commit = await async_client.commits.promote_all( to_environment="to_environment", + branch="branch", resource_id="resource_id", resource_type="audience", ) From dfff3b6aace731ce3cbb498d84760801806d0b0c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 18:41:53 +0000 Subject: [PATCH 089/101] feat(api): add support for broadcasts It is now possible to send, validate, list, retrieve, upsert, and cancel [broadcasts](https://docs.knock.app/concepts/broadcasts). --- .stats.yml | 4 +- api.md | 24 + src/knock_mapi/_client.py | 9 + src/knock_mapi/resources/__init__.py | 14 + src/knock_mapi/resources/broadcasts.py | 879 ++++++++++++++ src/knock_mapi/types/__init__.py | 27 + src/knock_mapi/types/broadcast.py | 105 ++ .../types/broadcast_cancel_params.py | 18 + .../types/broadcast_cancel_response.py | 15 + src/knock_mapi/types/broadcast_list_params.py | 37 + .../types/broadcast_request_param.py | 75 ++ .../types/broadcast_retrieve_params.py | 28 + src/knock_mapi/types/broadcast_send_params.py | 29 + .../types/broadcast_send_response.py | 15 + .../types/broadcast_upsert_params.py | 27 + .../types/broadcast_upsert_response.py | 15 + .../types/broadcast_validate_params.py | 24 + .../types/broadcast_validate_response.py | 15 + tests/api_resources/test_broadcasts.py | 1056 +++++++++++++++++ 19 files changed, 2414 insertions(+), 2 deletions(-) create mode 100644 src/knock_mapi/resources/broadcasts.py create mode 100644 src/knock_mapi/types/broadcast.py create mode 100644 src/knock_mapi/types/broadcast_cancel_params.py create mode 100644 src/knock_mapi/types/broadcast_cancel_response.py create mode 100644 src/knock_mapi/types/broadcast_list_params.py create mode 100644 src/knock_mapi/types/broadcast_request_param.py create mode 100644 src/knock_mapi/types/broadcast_retrieve_params.py create mode 100644 src/knock_mapi/types/broadcast_send_params.py create mode 100644 src/knock_mapi/types/broadcast_send_response.py create mode 100644 src/knock_mapi/types/broadcast_upsert_params.py create mode 100644 src/knock_mapi/types/broadcast_upsert_response.py create mode 100644 src/knock_mapi/types/broadcast_validate_params.py create mode 100644 src/knock_mapi/types/broadcast_validate_response.py create mode 100644 tests/api_resources/test_broadcasts.py diff --git a/.stats.yml b/.stats.yml index c971f40..f560b2c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 45 +configured_endpoints: 51 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-3ecceed264a62adba59c787f105549f62109739328db523366159f22c2ed1ee6.yml openapi_spec_hash: 80b5362bf4f1ce98bc016406dc7e1bed -config_hash: 34780c6a4340e5f9ddfb18f6b534eea5 +config_hash: 2d70cc65ea0584a49b00c63529ca6799 diff --git a/api.md b/api.md index c194a69..7c3547f 100644 --- a/api.md +++ b/api.md @@ -284,3 +284,27 @@ Methods: - client.branches.retrieve(branch_slug, \*\*params) -> Branch - client.branches.list(\*\*params) -> SyncEntriesCursor[Branch] - client.branches.delete(branch_slug, \*\*params) -> None + +# Broadcasts + +Types: + +```python +from knock_mapi.types import ( + Broadcast, + BroadcastRequest, + BroadcastCancelResponse, + BroadcastSendResponse, + BroadcastUpsertResponse, + BroadcastValidateResponse, +) +``` + +Methods: + +- client.broadcasts.retrieve(broadcast_key, \*\*params) -> Broadcast +- client.broadcasts.list(\*\*params) -> SyncEntriesCursor[Broadcast] +- client.broadcasts.cancel(broadcast_key, \*\*params) -> BroadcastCancelResponse +- client.broadcasts.send(broadcast_key, \*\*params) -> BroadcastSendResponse +- client.broadcasts.upsert(broadcast_key, \*\*params) -> BroadcastUpsertResponse +- client.broadcasts.validate(broadcast_key, \*\*params) -> BroadcastValidateResponse diff --git a/src/knock_mapi/_client.py b/src/knock_mapi/_client.py index b49d2ae..7d66473 100644 --- a/src/knock_mapi/_client.py +++ b/src/knock_mapi/_client.py @@ -30,6 +30,7 @@ channels, partials, variables, + broadcasts, environments, translations, email_layouts, @@ -72,6 +73,7 @@ class KnockMgmt(SyncAPIClient): variables: variables.VariablesResource guides: guides.GuidesResource branches: branches.BranchesResource + broadcasts: broadcasts.BroadcastsResource with_raw_response: KnockMgmtWithRawResponse with_streaming_response: KnockMgmtWithStreamedResponse @@ -143,6 +145,7 @@ def __init__( self.variables = variables.VariablesResource(self) self.guides = guides.GuidesResource(self) self.branches = branches.BranchesResource(self) + self.broadcasts = broadcasts.BroadcastsResource(self) self.with_raw_response = KnockMgmtWithRawResponse(self) self.with_streaming_response = KnockMgmtWithStreamedResponse(self) @@ -266,6 +269,7 @@ class AsyncKnockMgmt(AsyncAPIClient): variables: variables.AsyncVariablesResource guides: guides.AsyncGuidesResource branches: branches.AsyncBranchesResource + broadcasts: broadcasts.AsyncBroadcastsResource with_raw_response: AsyncKnockMgmtWithRawResponse with_streaming_response: AsyncKnockMgmtWithStreamedResponse @@ -337,6 +341,7 @@ def __init__( self.variables = variables.AsyncVariablesResource(self) self.guides = guides.AsyncGuidesResource(self) self.branches = branches.AsyncBranchesResource(self) + self.broadcasts = broadcasts.AsyncBroadcastsResource(self) self.with_raw_response = AsyncKnockMgmtWithRawResponse(self) self.with_streaming_response = AsyncKnockMgmtWithStreamedResponse(self) @@ -461,6 +466,7 @@ def __init__(self, client: KnockMgmt) -> None: self.variables = variables.VariablesResourceWithRawResponse(client.variables) self.guides = guides.GuidesResourceWithRawResponse(client.guides) self.branches = branches.BranchesResourceWithRawResponse(client.branches) + self.broadcasts = broadcasts.BroadcastsResourceWithRawResponse(client.broadcasts) class AsyncKnockMgmtWithRawResponse: @@ -479,6 +485,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.variables = variables.AsyncVariablesResourceWithRawResponse(client.variables) self.guides = guides.AsyncGuidesResourceWithRawResponse(client.guides) self.branches = branches.AsyncBranchesResourceWithRawResponse(client.branches) + self.broadcasts = broadcasts.AsyncBroadcastsResourceWithRawResponse(client.broadcasts) class KnockMgmtWithStreamedResponse: @@ -497,6 +504,7 @@ def __init__(self, client: KnockMgmt) -> None: self.variables = variables.VariablesResourceWithStreamingResponse(client.variables) self.guides = guides.GuidesResourceWithStreamingResponse(client.guides) self.branches = branches.BranchesResourceWithStreamingResponse(client.branches) + self.broadcasts = broadcasts.BroadcastsResourceWithStreamingResponse(client.broadcasts) class AsyncKnockMgmtWithStreamedResponse: @@ -515,6 +523,7 @@ def __init__(self, client: AsyncKnockMgmt) -> None: self.variables = variables.AsyncVariablesResourceWithStreamingResponse(client.variables) self.guides = guides.AsyncGuidesResourceWithStreamingResponse(client.guides) self.branches = branches.AsyncBranchesResourceWithStreamingResponse(client.branches) + self.broadcasts = broadcasts.AsyncBroadcastsResourceWithStreamingResponse(client.broadcasts) Client = KnockMgmt diff --git a/src/knock_mapi/resources/__init__.py b/src/knock_mapi/resources/__init__.py index a95769c..dbc0be6 100644 --- a/src/knock_mapi/resources/__init__.py +++ b/src/knock_mapi/resources/__init__.py @@ -72,6 +72,14 @@ WorkflowsResourceWithStreamingResponse, AsyncWorkflowsResourceWithStreamingResponse, ) +from .broadcasts import ( + BroadcastsResource, + AsyncBroadcastsResource, + BroadcastsResourceWithRawResponse, + AsyncBroadcastsResourceWithRawResponse, + BroadcastsResourceWithStreamingResponse, + AsyncBroadcastsResourceWithStreamingResponse, +) from .environments import ( EnvironmentsResource, AsyncEnvironmentsResource, @@ -198,4 +206,10 @@ "AsyncBranchesResourceWithRawResponse", "BranchesResourceWithStreamingResponse", "AsyncBranchesResourceWithStreamingResponse", + "BroadcastsResource", + "AsyncBroadcastsResource", + "BroadcastsResourceWithRawResponse", + "AsyncBroadcastsResourceWithRawResponse", + "BroadcastsResourceWithStreamingResponse", + "AsyncBroadcastsResourceWithStreamingResponse", ] diff --git a/src/knock_mapi/resources/broadcasts.py b/src/knock_mapi/resources/broadcasts.py new file mode 100644 index 0000000..abdc495 --- /dev/null +++ b/src/knock_mapi/resources/broadcasts.py @@ -0,0 +1,879 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime + +import httpx + +from ..types import ( + broadcast_list_params, + broadcast_send_params, + broadcast_cancel_params, + broadcast_upsert_params, + broadcast_retrieve_params, + broadcast_validate_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 SyncEntriesCursor, AsyncEntriesCursor +from .._base_client import AsyncPaginator, make_request_options +from ..types.broadcast import Broadcast +from ..types.broadcast_request_param import BroadcastRequestParam +from ..types.broadcast_send_response import BroadcastSendResponse +from ..types.broadcast_cancel_response import BroadcastCancelResponse +from ..types.broadcast_upsert_response import BroadcastUpsertResponse +from ..types.broadcast_validate_response import BroadcastValidateResponse + +__all__ = ["BroadcastsResource", "AsyncBroadcastsResource"] + + +class BroadcastsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> BroadcastsResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return BroadcastsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> BroadcastsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return BroadcastsResourceWithStreamingResponse(self) + + def retrieve( + self, + broadcast_key: str, + *, + environment: str, + annotate: bool | Omit = omit, + branch: str | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Get a broadcast by its key in a given environment. + + Args: + environment: The environment slug. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return self._get( + f"/v1/broadcasts/{broadcast_key}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "annotate": annotate, + "branch": branch, + "hide_uncommitted_changes": hide_uncommitted_changes, + }, + broadcast_retrieve_params.BroadcastRetrieveParams, + ), + ), + cast_to=Broadcast, + ) + + def list( + self, + *, + environment: str, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + branch: str | Omit = omit, + hide_uncommitted_changes: bool | 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, + ) -> SyncEntriesCursor[Broadcast]: + """Returns a paginated list of broadcasts available in a given environment. + + The + broadcasts are returned ordered by creation time (newest first). + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + before: The cursor to fetch entries before. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/broadcasts", + page=SyncEntriesCursor[Broadcast], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "annotate": annotate, + "before": before, + "branch": branch, + "hide_uncommitted_changes": hide_uncommitted_changes, + "limit": limit, + }, + broadcast_list_params.BroadcastListParams, + ), + ), + model=Broadcast, + ) + + def cancel( + self, + broadcast_key: str, + *, + environment: str, + branch: 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, + ) -> BroadcastCancelResponse: + """Cancels sending a scheduled broadcast. + + The broadcast will return to draft + status. + + Args: + environment: The environment slug. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return self._put( + f"/v1/broadcasts/{broadcast_key}/cancel", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_cancel_params.BroadcastCancelParams, + ), + ), + cast_to=BroadcastCancelResponse, + ) + + def send( + self, + broadcast_key: str, + *, + environment: str, + branch: str | Omit = omit, + send_at: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BroadcastSendResponse: + """ + Sends a broadcast immediately or schedules it to send at a future time. + + Args: + environment: The environment slug. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + send_at: When to send the broadcast. If provided, the broadcast will be scheduled to send + at this time. Must be in ISO 8601 UTC format. If not provided, the broadcast + will be sent immediately. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return self._put( + f"/v1/broadcasts/{broadcast_key}/send", + body=maybe_transform({"send_at": send_at}, broadcast_send_params.BroadcastSendParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_send_params.BroadcastSendParams, + ), + ), + cast_to=BroadcastSendResponse, + ) + + def upsert( + self, + broadcast_key: str, + *, + environment: str, + broadcast: BroadcastRequestParam, + annotate: bool | Omit = omit, + branch: 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, + ) -> BroadcastUpsertResponse: + """ + Updates a broadcast of a given key, or creates a new one if it does not yet + exist. + + Args: + environment: The environment slug. + + broadcast: A broadcast request for upserting a broadcast. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return self._put( + f"/v1/broadcasts/{broadcast_key}", + body=maybe_transform({"broadcast": broadcast}, broadcast_upsert_params.BroadcastUpsertParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "annotate": annotate, + "branch": branch, + }, + broadcast_upsert_params.BroadcastUpsertParams, + ), + ), + cast_to=BroadcastUpsertResponse, + ) + + def validate( + self, + broadcast_key: str, + *, + environment: str, + broadcast: BroadcastRequestParam, + branch: 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, + ) -> BroadcastValidateResponse: + """ + Validates a broadcast payload without persisting it. + + Args: + environment: The environment slug. + + broadcast: A broadcast request for upserting a broadcast. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return self._put( + f"/v1/broadcasts/{broadcast_key}/validate", + body=maybe_transform({"broadcast": broadcast}, broadcast_validate_params.BroadcastValidateParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_validate_params.BroadcastValidateParams, + ), + ), + cast_to=BroadcastValidateResponse, + ) + + +class AsyncBroadcastsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncBroadcastsResourceWithRawResponse: + """ + 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/knocklabs/knock-mgmt-python#accessing-raw-response-data-eg-headers + """ + return AsyncBroadcastsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncBroadcastsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/knocklabs/knock-mgmt-python#with_streaming_response + """ + return AsyncBroadcastsResourceWithStreamingResponse(self) + + async def retrieve( + self, + broadcast_key: str, + *, + environment: str, + annotate: bool | Omit = omit, + branch: str | Omit = omit, + hide_uncommitted_changes: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Broadcast: + """ + Get a broadcast by its key in a given environment. + + Args: + environment: The environment slug. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return await self._get( + f"/v1/broadcasts/{broadcast_key}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "annotate": annotate, + "branch": branch, + "hide_uncommitted_changes": hide_uncommitted_changes, + }, + broadcast_retrieve_params.BroadcastRetrieveParams, + ), + ), + cast_to=Broadcast, + ) + + def list( + self, + *, + environment: str, + after: str | Omit = omit, + annotate: bool | Omit = omit, + before: str | Omit = omit, + branch: str | Omit = omit, + hide_uncommitted_changes: bool | 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[Broadcast, AsyncEntriesCursor[Broadcast]]: + """Returns a paginated list of broadcasts available in a given environment. + + The + broadcasts are returned ordered by creation time (newest first). + + Args: + environment: The environment slug. + + after: The cursor to fetch entries after. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + before: The cursor to fetch entries before. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + hide_uncommitted_changes: Whether to hide uncommitted changes. When true, only committed changes will be + returned. When false, both committed and uncommitted changes will be returned. + + limit: The number of entries to fetch per-page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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/broadcasts", + page=AsyncEntriesCursor[Broadcast], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "environment": environment, + "after": after, + "annotate": annotate, + "before": before, + "branch": branch, + "hide_uncommitted_changes": hide_uncommitted_changes, + "limit": limit, + }, + broadcast_list_params.BroadcastListParams, + ), + ), + model=Broadcast, + ) + + async def cancel( + self, + broadcast_key: str, + *, + environment: str, + branch: 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, + ) -> BroadcastCancelResponse: + """Cancels sending a scheduled broadcast. + + The broadcast will return to draft + status. + + Args: + environment: The environment slug. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return await self._put( + f"/v1/broadcasts/{broadcast_key}/cancel", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_cancel_params.BroadcastCancelParams, + ), + ), + cast_to=BroadcastCancelResponse, + ) + + async def send( + self, + broadcast_key: str, + *, + environment: str, + branch: str | Omit = omit, + send_at: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> BroadcastSendResponse: + """ + Sends a broadcast immediately or schedules it to send at a future time. + + Args: + environment: The environment slug. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + send_at: When to send the broadcast. If provided, the broadcast will be scheduled to send + at this time. Must be in ISO 8601 UTC format. If not provided, the broadcast + will be sent immediately. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return await self._put( + f"/v1/broadcasts/{broadcast_key}/send", + body=await async_maybe_transform({"send_at": send_at}, broadcast_send_params.BroadcastSendParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_send_params.BroadcastSendParams, + ), + ), + cast_to=BroadcastSendResponse, + ) + + async def upsert( + self, + broadcast_key: str, + *, + environment: str, + broadcast: BroadcastRequestParam, + annotate: bool | Omit = omit, + branch: 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, + ) -> BroadcastUpsertResponse: + """ + Updates a broadcast of a given key, or creates a new one if it does not yet + exist. + + Args: + environment: The environment slug. + + broadcast: A broadcast request for upserting a broadcast. + + annotate: Whether to annotate the resource. Only used in the Knock CLI. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return await self._put( + f"/v1/broadcasts/{broadcast_key}", + body=await async_maybe_transform({"broadcast": broadcast}, broadcast_upsert_params.BroadcastUpsertParams), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "annotate": annotate, + "branch": branch, + }, + broadcast_upsert_params.BroadcastUpsertParams, + ), + ), + cast_to=BroadcastUpsertResponse, + ) + + async def validate( + self, + broadcast_key: str, + *, + environment: str, + broadcast: BroadcastRequestParam, + branch: 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, + ) -> BroadcastValidateResponse: + """ + Validates a broadcast payload without persisting it. + + Args: + environment: The environment slug. + + broadcast: A broadcast request for upserting a broadcast. + + branch: The slug of a branch to use. This option can only be used when `environment` is + `"development"`. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters 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 broadcast_key: + raise ValueError(f"Expected a non-empty value for `broadcast_key` but received {broadcast_key!r}") + return await self._put( + f"/v1/broadcasts/{broadcast_key}/validate", + body=await async_maybe_transform( + {"broadcast": broadcast}, broadcast_validate_params.BroadcastValidateParams + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "environment": environment, + "branch": branch, + }, + broadcast_validate_params.BroadcastValidateParams, + ), + ), + cast_to=BroadcastValidateResponse, + ) + + +class BroadcastsResourceWithRawResponse: + def __init__(self, broadcasts: BroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.retrieve = to_raw_response_wrapper( + broadcasts.retrieve, + ) + self.list = to_raw_response_wrapper( + broadcasts.list, + ) + self.cancel = to_raw_response_wrapper( + broadcasts.cancel, + ) + self.send = to_raw_response_wrapper( + broadcasts.send, + ) + self.upsert = to_raw_response_wrapper( + broadcasts.upsert, + ) + self.validate = to_raw_response_wrapper( + broadcasts.validate, + ) + + +class AsyncBroadcastsResourceWithRawResponse: + def __init__(self, broadcasts: AsyncBroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.retrieve = async_to_raw_response_wrapper( + broadcasts.retrieve, + ) + self.list = async_to_raw_response_wrapper( + broadcasts.list, + ) + self.cancel = async_to_raw_response_wrapper( + broadcasts.cancel, + ) + self.send = async_to_raw_response_wrapper( + broadcasts.send, + ) + self.upsert = async_to_raw_response_wrapper( + broadcasts.upsert, + ) + self.validate = async_to_raw_response_wrapper( + broadcasts.validate, + ) + + +class BroadcastsResourceWithStreamingResponse: + def __init__(self, broadcasts: BroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.retrieve = to_streamed_response_wrapper( + broadcasts.retrieve, + ) + self.list = to_streamed_response_wrapper( + broadcasts.list, + ) + self.cancel = to_streamed_response_wrapper( + broadcasts.cancel, + ) + self.send = to_streamed_response_wrapper( + broadcasts.send, + ) + self.upsert = to_streamed_response_wrapper( + broadcasts.upsert, + ) + self.validate = to_streamed_response_wrapper( + broadcasts.validate, + ) + + +class AsyncBroadcastsResourceWithStreamingResponse: + def __init__(self, broadcasts: AsyncBroadcastsResource) -> None: + self._broadcasts = broadcasts + + self.retrieve = async_to_streamed_response_wrapper( + broadcasts.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + broadcasts.list, + ) + self.cancel = async_to_streamed_response_wrapper( + broadcasts.cancel, + ) + self.send = async_to_streamed_response_wrapper( + broadcasts.send, + ) + self.upsert = async_to_streamed_response_wrapper( + broadcasts.upsert, + ) + self.validate = async_to_streamed_response_wrapper( + broadcasts.validate, + ) diff --git a/src/knock_mapi/types/__init__.py b/src/knock_mapi/types/__init__.py index e053a79..b46991e 100644 --- a/src/knock_mapi/types/__init__.py +++ b/src/knock_mapi/types/__init__.py @@ -4,11 +4,16 @@ from . import ( workflow, + broadcast, workflow_branch_step, + broadcast_send_response, workflow_upsert_response, + broadcast_cancel_response, + broadcast_upsert_response, workflow_activate_response, workflow_retrieve_response, workflow_validate_response, + broadcast_validate_response, ) from .. import _compat from .guide import Guide as Guide @@ -20,6 +25,7 @@ from .duration import Duration as Duration from .variable import Variable as Variable from .workflow import Workflow as Workflow +from .broadcast import Broadcast as Broadcast from .condition import Condition as Condition from .guide_step import GuideStep as GuideStep from .environment import Environment as Environment @@ -69,6 +75,8 @@ from .variable_list_params import VariableListParams as VariableListParams from .workflow_branch_step import WorkflowBranchStep as WorkflowBranchStep from .workflow_list_params import WorkflowListParams as WorkflowListParams +from .broadcast_list_params import BroadcastListParams as BroadcastListParams +from .broadcast_send_params import BroadcastSendParams as BroadcastSendParams from .chat_channel_settings import ChatChannelSettings as ChatChannelSettings from .condition_group_param import ConditionGroupParam as ConditionGroupParam from .guide_activate_params import GuideActivateParams as GuideActivateParams @@ -87,6 +95,10 @@ from .workflow_throttle_step import WorkflowThrottleStep as WorkflowThrottleStep from .workflow_upsert_params import WorkflowUpsertParams as WorkflowUpsertParams from .api_key_exchange_params import APIKeyExchangeParams as APIKeyExchangeParams +from .broadcast_cancel_params import BroadcastCancelParams as BroadcastCancelParams +from .broadcast_request_param import BroadcastRequestParam as BroadcastRequestParam +from .broadcast_send_response import BroadcastSendResponse as BroadcastSendResponse +from .broadcast_upsert_params import BroadcastUpsertParams as BroadcastUpsertParams from .environment_list_params import EnvironmentListParams as EnvironmentListParams from .guide_activate_response import GuideActivateResponse as GuideActivateResponse from .guide_validate_response import GuideValidateResponse as GuideValidateResponse @@ -106,6 +118,10 @@ from .workflow_upsert_response import WorkflowUpsertResponse as WorkflowUpsertResponse from .workflow_validate_params import WorkflowValidateParams as WorkflowValidateParams from .api_key_exchange_response import APIKeyExchangeResponse as APIKeyExchangeResponse +from .broadcast_cancel_response import BroadcastCancelResponse as BroadcastCancelResponse +from .broadcast_retrieve_params import BroadcastRetrieveParams as BroadcastRetrieveParams +from .broadcast_upsert_response import BroadcastUpsertResponse as BroadcastUpsertResponse +from .broadcast_validate_params import BroadcastValidateParams as BroadcastValidateParams from .channel_group_list_params import ChannelGroupListParams as ChannelGroupListParams from .commit_promote_all_params import CommitPromoteAllParams as CommitPromoteAllParams from .partial_validate_response import PartialValidateResponse as PartialValidateResponse @@ -125,6 +141,7 @@ from .workflow_branch_step_param import WorkflowBranchStepParam as WorkflowBranchStepParam from .workflow_retrieve_response import WorkflowRetrieveResponse as WorkflowRetrieveResponse from .workflow_validate_response import WorkflowValidateResponse as WorkflowValidateResponse +from .broadcast_validate_response import BroadcastValidateResponse as BroadcastValidateResponse from .chat_channel_settings_param import ChatChannelSettingsParam as ChatChannelSettingsParam from .commit_promote_all_response import CommitPromoteAllResponse as CommitPromoteAllResponse from .commit_promote_one_response import CommitPromoteOneResponse as CommitPromoteOneResponse @@ -165,6 +182,11 @@ workflow_activate_response.WorkflowActivateResponse.update_forward_refs() # type: ignore workflow_upsert_response.WorkflowUpsertResponse.update_forward_refs() # type: ignore workflow_validate_response.WorkflowValidateResponse.update_forward_refs() # type: ignore + broadcast.Broadcast.update_forward_refs() # type: ignore + broadcast_cancel_response.BroadcastCancelResponse.update_forward_refs() # type: ignore + broadcast_send_response.BroadcastSendResponse.update_forward_refs() # type: ignore + broadcast_upsert_response.BroadcastUpsertResponse.update_forward_refs() # type: ignore + broadcast_validate_response.BroadcastValidateResponse.update_forward_refs() # type: ignore else: workflow.Workflow.model_rebuild(_parent_namespace_depth=0) workflow_branch_step.WorkflowBranchStep.model_rebuild(_parent_namespace_depth=0) @@ -172,3 +194,8 @@ workflow_activate_response.WorkflowActivateResponse.model_rebuild(_parent_namespace_depth=0) workflow_upsert_response.WorkflowUpsertResponse.model_rebuild(_parent_namespace_depth=0) workflow_validate_response.WorkflowValidateResponse.model_rebuild(_parent_namespace_depth=0) + broadcast.Broadcast.model_rebuild(_parent_namespace_depth=0) + broadcast_cancel_response.BroadcastCancelResponse.model_rebuild(_parent_namespace_depth=0) + broadcast_send_response.BroadcastSendResponse.model_rebuild(_parent_namespace_depth=0) + broadcast_upsert_response.BroadcastUpsertResponse.model_rebuild(_parent_namespace_depth=0) + broadcast_validate_response.BroadcastValidateResponse.model_rebuild(_parent_namespace_depth=0) diff --git a/src/knock_mapi/types/broadcast.py b/src/knock_mapi/types/broadcast.py new file mode 100644 index 0000000..05ef994 --- /dev/null +++ b/src/knock_mapi/types/broadcast.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from .._models import BaseModel +from .workflow_sms_step import WorkflowSMSStep +from .workflow_chat_step import WorkflowChatStep +from .workflow_push_step import WorkflowPushStep +from .workflow_delay_step import WorkflowDelayStep +from .workflow_email_step import WorkflowEmailStep +from .workflow_webhook_step import WorkflowWebhookStep +from .workflow_in_app_feed_step import WorkflowInAppFeedStep + +__all__ = ["Broadcast", "Step", "Settings"] + +Step: TypeAlias = Union[ + WorkflowWebhookStep, + WorkflowInAppFeedStep, + WorkflowChatStep, + WorkflowSMSStep, + WorkflowPushStep, + WorkflowEmailStep, + "WorkflowBranchStep", + WorkflowDelayStep, +] + + +class Settings(BaseModel): + is_commercial: Optional[bool] = None + """Whether the broadcast is commercial. Defaults to true.""" + + override_preferences: Optional[bool] = None + """Whether to ignore recipient preferences for a given type of notification. + + If true, will send for every channel in the workflow even if the recipient has + opted out of a certain kind. Defaults to false. + """ + + +class Broadcast(BaseModel): + created_at: datetime + """The timestamp of when the broadcast was created. (read-only).""" + + environment: str + """The slug of the environment in which the broadcast exists. (read-only).""" + + key: str + """The unique key string for the broadcast object. + + Must be at minimum 3 characters and at maximum 255 characters in length. Must be + in the format of ^[a-z0-9_-]+$. + """ + + name: str + """A name for the broadcast. Must be at maximum 255 characters in length.""" + + sha: str + """The SHA hash of the workflow data. (read-only).""" + + status: Literal["draft", "scheduled", "sent"] + """The current status of the broadcast. One of: `draft`, `scheduled`, `sent`.""" + + steps: List[Step] + """A list of broadcast step objects in the broadcast. + + Broadcasts only support channel, branch, and delay steps. + """ + + updated_at: datetime + """The timestamp of when the broadcast was last updated. (read-only).""" + + valid: bool + """Whether the broadcast and its steps are in a valid state. (read-only).""" + + archived_at: Optional[datetime] = None + """The timestamp of when the broadcast was archived.""" + + categories: Optional[List[str]] = None + """A list of categories that the broadcast belongs to.""" + + description: Optional[str] = None + """An arbitrary string attached to a broadcast object. + + Useful for adding notes about the broadcast for internal purposes. Maximum of + 280 characters allowed. + """ + + scheduled_at: Optional[datetime] = None + """The timestamp of when the broadcast is scheduled to be sent.""" + + sent_at: Optional[datetime] = None + """The timestamp of when the broadcast was sent. (read-only).""" + + settings: Optional[Settings] = None + """A map of broadcast settings.""" + + target_audience_key: Optional[str] = None + """The key of the audience to target for this broadcast.""" + + +from .workflow_branch_step import WorkflowBranchStep diff --git a/src/knock_mapi/types/broadcast_cancel_params.py b/src/knock_mapi/types/broadcast_cancel_params.py new file mode 100644 index 0000000..cda2c71 --- /dev/null +++ b/src/knock_mapi/types/broadcast_cancel_params.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastCancelParams"] + + +class BroadcastCancelParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ diff --git a/src/knock_mapi/types/broadcast_cancel_response.py b/src/knock_mapi/types/broadcast_cancel_response.py new file mode 100644 index 0000000..a96d07b --- /dev/null +++ b/src/knock_mapi/types/broadcast_cancel_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["BroadcastCancelResponse"] + + +class BroadcastCancelResponse(BaseModel): + broadcast: "Broadcast" + """A broadcast object.""" + + +from .broadcast import Broadcast diff --git a/src/knock_mapi/types/broadcast_list_params.py b/src/knock_mapi/types/broadcast_list_params.py new file mode 100644 index 0000000..b9f606a --- /dev/null +++ b/src/knock_mapi/types/broadcast_list_params.py @@ -0,0 +1,37 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastListParams"] + + +class BroadcastListParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + after: str + """The cursor to fetch entries after.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + before: str + """The cursor to fetch entries before.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + + hide_uncommitted_changes: bool + """Whether to hide uncommitted changes. + + When true, only committed changes will be returned. When false, both committed + and uncommitted changes will be returned. + """ + + limit: int + """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/broadcast_request_param.py b/src/knock_mapi/types/broadcast_request_param.py new file mode 100644 index 0000000..0a981a5 --- /dev/null +++ b/src/knock_mapi/types/broadcast_request_param.py @@ -0,0 +1,75 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union, Iterable +from datetime import datetime +from typing_extensions import Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo +from .workflow_sms_step_param import WorkflowSMSStepParam +from .workflow_chat_step_param import WorkflowChatStepParam +from .workflow_push_step_param import WorkflowPushStepParam +from .workflow_delay_step_param import WorkflowDelayStepParam +from .workflow_email_step_param import WorkflowEmailStepParam +from .workflow_webhook_step_param import WorkflowWebhookStepParam +from .workflow_in_app_feed_step_param import WorkflowInAppFeedStepParam + +__all__ = ["BroadcastRequestParam", "Step", "Settings"] + +Step: TypeAlias = Union[ + WorkflowWebhookStepParam, + WorkflowInAppFeedStepParam, + WorkflowChatStepParam, + WorkflowSMSStepParam, + WorkflowPushStepParam, + WorkflowEmailStepParam, + "WorkflowBranchStepParam", + WorkflowDelayStepParam, +] + + +class Settings(TypedDict, total=False): + is_commercial: bool + """Whether the broadcast is commercial. Defaults to true.""" + + override_preferences: bool + """Whether to ignore recipient preferences for a given type of notification. + + If true, will send for every channel in the workflow even if the recipient has + opted out of a certain kind. Defaults to false. + """ + + +class BroadcastRequestParam(TypedDict, total=False): + name: Required[str] + """A name for the broadcast. Must be at maximum 255 characters in length.""" + + steps: Required[Iterable[Step]] + """A list of broadcast step objects in the broadcast. + + Broadcasts only support channel, branch, and delay steps. + """ + + categories: SequenceNotStr[str] + """A list of categories that the broadcast belongs to.""" + + description: str + """An arbitrary string attached to a broadcast object. + + Useful for adding notes about the broadcast for internal purposes. Maximum of + 280 characters allowed. + """ + + scheduled_at: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """The timestamp of when the broadcast is scheduled to be sent.""" + + settings: Settings + """A map of broadcast settings.""" + + target_audience_key: str + """The key of the audience to target for this broadcast.""" + + +from .workflow_branch_step_param import WorkflowBranchStepParam diff --git a/src/knock_mapi/types/broadcast_retrieve_params.py b/src/knock_mapi/types/broadcast_retrieve_params.py new file mode 100644 index 0000000..0cba386 --- /dev/null +++ b/src/knock_mapi/types/broadcast_retrieve_params.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastRetrieveParams"] + + +class BroadcastRetrieveParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + + hide_uncommitted_changes: bool + """Whether to hide uncommitted changes. + + When true, only committed changes will be returned. When false, both committed + and uncommitted changes will be returned. + """ diff --git a/src/knock_mapi/types/broadcast_send_params.py b/src/knock_mapi/types/broadcast_send_params.py new file mode 100644 index 0000000..9270584 --- /dev/null +++ b/src/knock_mapi/types/broadcast_send_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Required, Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["BroadcastSendParams"] + + +class BroadcastSendParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + + send_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """When to send the broadcast. + + If provided, the broadcast will be scheduled to send at this time. Must be in + ISO 8601 UTC format. If not provided, the broadcast will be sent immediately. + """ diff --git a/src/knock_mapi/types/broadcast_send_response.py b/src/knock_mapi/types/broadcast_send_response.py new file mode 100644 index 0000000..6c21539 --- /dev/null +++ b/src/knock_mapi/types/broadcast_send_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["BroadcastSendResponse"] + + +class BroadcastSendResponse(BaseModel): + broadcast: "Broadcast" + """A broadcast object.""" + + +from .broadcast import Broadcast diff --git a/src/knock_mapi/types/broadcast_upsert_params.py b/src/knock_mapi/types/broadcast_upsert_params.py new file mode 100644 index 0000000..87003d0 --- /dev/null +++ b/src/knock_mapi/types/broadcast_upsert_params.py @@ -0,0 +1,27 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastUpsertParams"] + + +class BroadcastUpsertParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + broadcast: Required["BroadcastRequestParam"] + """A broadcast request for upserting a broadcast.""" + + annotate: bool + """Whether to annotate the resource. Only used in the Knock CLI.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + + +from .broadcast_request_param import BroadcastRequestParam diff --git a/src/knock_mapi/types/broadcast_upsert_response.py b/src/knock_mapi/types/broadcast_upsert_response.py new file mode 100644 index 0000000..0fff352 --- /dev/null +++ b/src/knock_mapi/types/broadcast_upsert_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["BroadcastUpsertResponse"] + + +class BroadcastUpsertResponse(BaseModel): + broadcast: "Broadcast" + """A broadcast object.""" + + +from .broadcast import Broadcast diff --git a/src/knock_mapi/types/broadcast_validate_params.py b/src/knock_mapi/types/broadcast_validate_params.py new file mode 100644 index 0000000..45eae54 --- /dev/null +++ b/src/knock_mapi/types/broadcast_validate_params.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["BroadcastValidateParams"] + + +class BroadcastValidateParams(TypedDict, total=False): + environment: Required[str] + """The environment slug.""" + + broadcast: Required["BroadcastRequestParam"] + """A broadcast request for upserting a broadcast.""" + + branch: str + """The slug of a branch to use. + + This option can only be used when `environment` is `"development"`. + """ + + +from .broadcast_request_param import BroadcastRequestParam diff --git a/src/knock_mapi/types/broadcast_validate_response.py b/src/knock_mapi/types/broadcast_validate_response.py new file mode 100644 index 0000000..b958730 --- /dev/null +++ b/src/knock_mapi/types/broadcast_validate_response.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel + +__all__ = ["BroadcastValidateResponse"] + + +class BroadcastValidateResponse(BaseModel): + broadcast: "Broadcast" + """A broadcast object.""" + + +from .broadcast import Broadcast diff --git a/tests/api_resources/test_broadcasts.py b/tests/api_resources/test_broadcasts.py new file mode 100644 index 0000000..9716fe5 --- /dev/null +++ b/tests/api_resources/test_broadcasts.py @@ -0,0 +1,1056 @@ +# 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 knock_mapi import KnockMgmt, AsyncKnockMgmt +from tests.utils import assert_matches_type +from knock_mapi.types import ( + Broadcast, + BroadcastSendResponse, + BroadcastCancelResponse, + BroadcastUpsertResponse, + BroadcastValidateResponse, +) +from knock_mapi._utils import parse_datetime +from knock_mapi.pagination import SyncEntriesCursor, AsyncEntriesCursor + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestBroadcasts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_retrieve(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.retrieve( + broadcast_key="broadcast_key", + environment="development", + annotate=True, + branch="feature-branch", + hide_uncommitted_changes=True, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_retrieve(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_retrieve(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_retrieve(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + client.broadcasts.with_raw_response.retrieve( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_list(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.list( + environment="development", + ) + assert_matches_type(SyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_list_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.list( + environment="development", + after="after", + annotate=True, + before="before", + branch="feature-branch", + hide_uncommitted_changes=True, + limit=0, + ) + assert_matches_type(SyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_list(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(SyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_list(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(SyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_cancel(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.cancel( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_cancel_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.cancel( + broadcast_key="broadcast_key", + environment="development", + branch="feature-branch", + ) + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_cancel(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.cancel( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_cancel(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.cancel( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_cancel(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + client.broadcasts.with_raw_response.cancel( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_send(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.send( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_send_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.send( + broadcast_key="broadcast_key", + environment="development", + branch="feature-branch", + send_at=parse_datetime("2024-03-20T10:00:00Z"), + ) + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_send(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.send( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_send(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.send( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_send(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + client.broadcasts.with_raw_response.send( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_upsert(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "name": "Channel 1", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], + "categories": ["announcement"], + "description": "A broadcast to all users", + "scheduled_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "settings": { + "is_commercial": True, + "override_preferences": False, + }, + "target_audience_key": "all-users", + }, + annotate=True, + branch="feature-branch", + ) + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_upsert(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_upsert(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_upsert(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + client.broadcasts.with_raw_response.upsert( + broadcast_key="", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_validate(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_method_validate_with_all_params(self, client: KnockMgmt) -> None: + broadcast = client.broadcasts.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "name": "Channel 1", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], + "categories": ["announcement"], + "description": "A broadcast to all users", + "scheduled_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "settings": { + "is_commercial": True, + "override_preferences": False, + }, + "target_audience_key": "all-users", + }, + branch="feature-branch", + ) + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_raw_response_validate(self, client: KnockMgmt) -> None: + response = client.broadcasts.with_raw_response.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = response.parse() + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_streaming_response_validate(self, client: KnockMgmt) -> None: + with client.broadcasts.with_streaming_response.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = response.parse() + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + def test_path_params_validate(self, client: KnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + client.broadcasts.with_raw_response.validate( + broadcast_key="", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + +class TestAsyncBroadcasts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.retrieve( + broadcast_key="broadcast_key", + environment="development", + annotate=True, + branch="feature-branch", + hide_uncommitted_changes=True, + ) + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.retrieve( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(Broadcast, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + await async_client.broadcasts.with_raw_response.retrieve( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_list(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.list( + environment="development", + ) + assert_matches_type(AsyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.list( + environment="development", + after="after", + annotate=True, + before="before", + branch="feature-branch", + hide_uncommitted_changes=True, + limit=0, + ) + assert_matches_type(AsyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.list( + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(AsyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.list( + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(AsyncEntriesCursor[Broadcast], broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_cancel(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.cancel( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_cancel_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.cancel( + broadcast_key="broadcast_key", + environment="development", + branch="feature-branch", + ) + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_cancel(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.cancel( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_cancel(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.cancel( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(BroadcastCancelResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_cancel(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + await async_client.broadcasts.with_raw_response.cancel( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_send(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.send( + broadcast_key="broadcast_key", + environment="development", + ) + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_send_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.send( + broadcast_key="broadcast_key", + environment="development", + branch="feature-branch", + send_at=parse_datetime("2024-03-20T10:00:00Z"), + ) + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_send(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.send( + broadcast_key="broadcast_key", + environment="development", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_send(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.send( + broadcast_key="broadcast_key", + environment="development", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(BroadcastSendResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_send(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + await async_client.broadcasts.with_raw_response.send( + broadcast_key="", + environment="development", + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_upsert(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "name": "Channel 1", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], + "categories": ["announcement"], + "description": "A broadcast to all users", + "scheduled_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "settings": { + "is_commercial": True, + "override_preferences": False, + }, + "target_audience_key": "all-users", + }, + annotate=True, + branch="feature-branch", + ) + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_upsert(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_upsert(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.upsert( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(BroadcastUpsertResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_upsert(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + await async_client.broadcasts.with_raw_response.upsert( + broadcast_key="", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_validate(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgmt) -> None: + broadcast = await async_client.broadcasts.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": { + "markdown_body": "Hello **{{ recipient.name }}**", + "action_buttons": [ + { + "action": "https://example.com", + "label": "Button 1", + } + ], + "action_url": "{{ vars.app_url }}", + }, + "type": "channel", + "channel_group_key": None, + "channel_key": "in-app-feed", + "channel_overrides": {"link_tracking": True}, + "channel_type": "in_app_feed", + "conditions": { + "all": [ + { + "operator": "equal_to", + "variable": "recipient.property", + "argument": "some_property", + } + ] + }, + "description": "This is a description of the channel step", + "name": "Channel 1", + "send_windows": [ + { + "day": "monday", + "type": "send", + "from": "18:11:19.117Z", + "until": "18:11:19.117Z", + } + ], + } + ], + "categories": ["announcement"], + "description": "A broadcast to all users", + "scheduled_at": parse_datetime("2019-12-27T18:11:19.117Z"), + "settings": { + "is_commercial": True, + "override_preferences": False, + }, + "target_audience_key": "all-users", + }, + branch="feature-branch", + ) + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_raw_response_validate(self, async_client: AsyncKnockMgmt) -> None: + response = await async_client.broadcasts.with_raw_response.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + broadcast = await response.parse() + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_streaming_response_validate(self, async_client: AsyncKnockMgmt) -> None: + async with async_client.broadcasts.with_streaming_response.validate( + broadcast_key="broadcast_key", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + broadcast = await response.parse() + assert_matches_type(BroadcastValidateResponse, broadcast, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism doesn't support callbacks yet") + @parametrize + async def test_path_params_validate(self, async_client: AsyncKnockMgmt) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `broadcast_key` but received ''"): + await async_client.broadcasts.with_raw_response.validate( + broadcast_key="", + environment="development", + broadcast={ + "name": "My Broadcast", + "steps": [ + { + "ref": "channel_1", + "template": {"markdown_body": "Hello **{{ recipient.name }}**"}, + "type": "channel", + } + ], + }, + ) From 6e2e025ae38d38d50423ff08c4c0171eac8ba5bb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 23:28:32 +0000 Subject: [PATCH 090/101] chore(internal): codegen related update --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2e64eae..2e67fef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From ee545af593640a9128ffcc8e14b0793e91ec8a5f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 16:51:10 +0000 Subject: [PATCH 091/101] fix: ensure streams are always closed --- src/knock_mapi/_streaming.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/knock_mapi/_streaming.py b/src/knock_mapi/_streaming.py index 9cea96a..ab4cacb 100644 --- a/src/knock_mapi/_streaming.py +++ b/src/knock_mapi/_streaming.py @@ -54,11 +54,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - response.close() + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -117,11 +118,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - await response.aclose() + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self From 828d403035cb6fcb789b92069124eba8c79088a6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Nov 2025 18:46:37 +0000 Subject: [PATCH 092/101] chore(deps): mypy 1.18.1 has a regression, pin to 1.17 --- pyproject.toml | 2 +- requirements-dev.lock | 4 +++- requirements.lock | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2e67fef..af1fec5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", diff --git a/requirements-dev.lock b/requirements-dev.lock index 473acbd..b3d594c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -72,7 +72,7 @@ mdurl==0.1.2 multidict==6.4.4 # via aiohttp # via yarl -mypy==1.14.1 +mypy==1.17.0 mypy-extensions==1.0.0 # via mypy nodeenv==1.8.0 @@ -81,6 +81,8 @@ nox==2023.4.22 packaging==23.2 # via nox # via pytest +pathspec==0.12.1 + # via mypy platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 diff --git a/requirements.lock b/requirements.lock index d8a610d..71fc210 100644 --- a/requirements.lock +++ b/requirements.lock @@ -55,21 +55,21 @@ multidict==6.4.4 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via knock-mapi -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic sniffio==1.3.0 # via anyio # via knock-mapi -typing-extensions==4.12.2 +typing-extensions==4.15.0 # via anyio # via knock-mapi # via multidict # via pydantic # via pydantic-core # via typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic yarl==1.20.0 # via aiohttp From 0d8db9179968f0f2852473054d207ca5e8de3652 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 21:06:10 +0000 Subject: [PATCH 093/101] feat(api): api update --- .stats.yml | 4 ++-- src/knock_mapi/types/auth_verify_response.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f560b2c..0fe50c7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 51 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-3ecceed264a62adba59c787f105549f62109739328db523366159f22c2ed1ee6.yml -openapi_spec_hash: 80b5362bf4f1ce98bc016406dc7e1bed +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-mapi-6b4b6e690b61c6e006e20c3da499cf64a945630a1827baf5a58d5b33d312f75f.yml +openapi_spec_hash: c9115053b9370cffdb7e48176210c788 config_hash: 2d70cc65ea0584a49b00c63529ca6799 diff --git a/src/knock_mapi/types/auth_verify_response.py b/src/knock_mapi/types/auth_verify_response.py index eaea719..4f67ec3 100644 --- a/src/knock_mapi/types/auth_verify_response.py +++ b/src/knock_mapi/types/auth_verify_response.py @@ -30,6 +30,9 @@ class AccountFeatures(BaseModel): guides_monthly_notified_recipients_limit: Optional[int] = None """Monthly limit for guide notification recipients, null for unlimited.""" + guides_per_tenant_scope_allowed: Optional[bool] = None + """Whether per-tenant scope for guide messages is allowed.""" + heap_extension_allowed: Optional[bool] = None """Whether Heap integration extension is available.""" From b80f066cb4de4d97dc2171086d6b48dec1341029 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:06:15 +0000 Subject: [PATCH 094/101] chore: update lockfile --- pyproject.toml | 14 +++--- requirements-dev.lock | 108 +++++++++++++++++++++++------------------- requirements.lock | 31 ++++++------ 3 files changed, 83 insertions(+), 70 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index af1fec5..4107f04 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,14 +7,16 @@ license = "Apache-2.0" authors = [ { name = "Knock Mgmt", email = "support@knock.app" }, ] + dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", ] + requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", diff --git a/requirements-dev.lock b/requirements-dev.lock index b3d594c..d83630a 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,40 +12,45 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via knock-mapi -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via knock-mapi -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2025.11.12 # via httpcore # via httpx -colorlog==6.7.0 +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 # via nox -dirty-equals==0.6.0 -distlib==0.3.7 +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via knock-mapi -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio # via pytest -execnet==2.1.1 +execnet==2.1.2 # via pytest-xdist -filelock==3.12.4 +filelock==3.19.1 # via virtualenv -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -58,82 +63,87 @@ httpx==0.28.1 # via respx httpx-aiohttp==0.1.9 # via knock-mapi -idna==3.4 +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==7.0.0 -iniconfig==2.0.0 +importlib-metadata==8.7.0 +iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl mypy==1.17.0 -mypy-extensions==1.0.0 +mypy-extensions==1.1.0 # via mypy -nodeenv==1.8.0 +nodeenv==1.9.1 # via pyright -nox==2023.4.22 -packaging==23.2 +nox==2025.11.12 +packaging==25.0 + # via dependency-groups # via nox # via pytest pathspec==0.12.1 # via mypy -platformdirs==3.11.0 +platformdirs==4.4.0 # via virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via pytest -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via knock-mapi -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic -pygments==2.18.0 +pygments==2.19.2 + # via pytest # via rich pyright==1.1.399 -pytest==8.3.3 +pytest==8.4.2 # via pytest-asyncio # via pytest-xdist -pytest-asyncio==0.24.0 -pytest-xdist==3.7.0 -python-dateutil==2.8.2 +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via time-machine -pytz==2023.3.post1 - # via dirty-equals respx==0.22.0 -rich==13.7.1 -ruff==0.9.4 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 +rich==14.2.0 +ruff==0.14.7 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via knock-mapi -time-machine==2.9.0 -tomli==2.0.2 +time-machine==2.19.0 +tomli==2.3.0 + # via dependency-groups # via mypy + # via nox # via pytest -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via knock-mapi # via multidict # via mypy # via pydantic # via pydantic-core # via pyright + # via pytest-asyncio # via typing-inspection -typing-inspection==0.4.1 + # via virtualenv +typing-inspection==0.4.2 # via pydantic -virtualenv==20.24.5 +virtualenv==20.35.4 # via nox -yarl==1.20.0 +yarl==1.22.0 # via aiohttp -zipp==3.17.0 +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index 71fc210..e3375f3 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,28 +12,28 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via knock-mapi -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via knock-mapi async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 +certifi==2025.11.12 # via httpcore # via httpx -distro==1.8.0 +distro==1.9.0 # via knock-mapi -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -45,25 +45,26 @@ httpx==0.28.1 # via knock-mapi httpx-aiohttp==0.1.9 # via knock-mapi -idna==3.4 +idna==3.11 # via anyio # via httpx # via yarl -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl pydantic==2.12.5 # via knock-mapi pydantic-core==2.41.5 # via pydantic -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via knock-mapi typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via knock-mapi # via multidict # via pydantic @@ -71,5 +72,5 @@ typing-extensions==4.15.0 # via typing-inspection typing-inspection==0.4.2 # via pydantic -yarl==1.20.0 +yarl==1.22.0 # via aiohttp From 36bffb16af013addda71caa6974d6ccb88c50f70 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:23:51 +0000 Subject: [PATCH 095/101] chore(docs): use environment variables for authentication in code snippets --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 46682cb..a679cde 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ pip install 'knock_mapi[aiohttp] @ git+ssh://git@github.com/knocklabs/knock-mgmt Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python +import os import asyncio from knock_mapi import DefaultAioHttpClient from knock_mapi import AsyncKnockMgmt @@ -93,7 +94,9 @@ from knock_mapi import AsyncKnockMgmt async def main() -> None: async with AsyncKnockMgmt( - service_token="My Service Token", + service_token=os.environ.get( + "KNOCK_SERVICE_TOKEN" + ), # This is the default and can be omitted http_client=DefaultAioHttpClient(), ) as client: page = await client.workflows.list( From f3148fd2c048f4572c24e7e970c12c8f8e9be96e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 18:39:26 +0000 Subject: [PATCH 096/101] fix(types): allow pyright to infer TypedDict types within SequenceNotStr --- src/knock_mapi/_types.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/knock_mapi/_types.py b/src/knock_mapi/_types.py index d12145b..5d8ccc3 100644 --- a/src/knock_mapi/_types.py +++ b/src/knock_mapi/_types.py @@ -243,6 +243,9 @@ class HttpxSendArgs(TypedDict, total=False): if TYPE_CHECKING: # This works because str.__contains__ does not accept object (either in typeshed or at runtime) # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. class SequenceNotStr(Protocol[_T_co]): @overload def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... @@ -251,8 +254,6 @@ def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... def __contains__(self, value: object, /) -> bool: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T_co]: ... - def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... - def count(self, value: Any, /) -> int: ... def __reversed__(self) -> Iterator[_T_co]: ... else: # just point this to a normal `Sequence` at runtime to avoid having to special case From 1d22dd0866f56e690df4a5bd3197b1a71f0fd19d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:28:38 +0000 Subject: [PATCH 097/101] chore: add missing docstrings --- .../types/api_key_exchange_response.py | 2 + src/knock_mapi/types/auth_verify_response.py | 4 ++ src/knock_mapi/types/branch.py | 2 + src/knock_mapi/types/broadcast.py | 4 ++ .../types/broadcast_cancel_response.py | 2 + .../types/broadcast_request_param.py | 4 ++ .../types/broadcast_send_response.py | 2 + .../types/broadcast_upsert_response.py | 2 + .../types/broadcast_validate_response.py | 2 + src/knock_mapi/types/channel.py | 2 + src/knock_mapi/types/channel_group.py | 2 + src/knock_mapi/types/channel_group_rule.py | 4 ++ src/knock_mapi/types/chat_channel_settings.py | 5 +++ .../types/chat_channel_settings_param.py | 5 +++ src/knock_mapi/types/chat_template.py | 2 + src/knock_mapi/types/chat_template_param.py | 2 + src/knock_mapi/types/commit.py | 6 +++ .../types/commit_commit_all_response.py | 2 + .../types/commit_promote_all_response.py | 2 + .../types/commit_promote_one_response.py | 2 + src/knock_mapi/types/condition.py | 2 + src/knock_mapi/types/condition_group.py | 6 +++ src/knock_mapi/types/condition_group_param.py | 6 +++ src/knock_mapi/types/condition_param.py | 2 + src/knock_mapi/types/duration.py | 2 + src/knock_mapi/types/duration_param.py | 2 + .../types/email_channel_settings.py | 5 +++ .../types/email_channel_settings_param.py | 5 +++ src/knock_mapi/types/email_layout.py | 2 + .../types/email_layout_upsert_params.py | 2 + .../types/email_layout_upsert_response.py | 2 + .../types/email_layout_validate_params.py | 2 + .../types/email_layout_validate_response.py | 2 + src/knock_mapi/types/email_template.py | 38 +++++++++++++++++++ src/knock_mapi/types/email_template_param.py | 38 +++++++++++++++++++ src/knock_mapi/types/environment.py | 2 + src/knock_mapi/types/guide.py | 4 ++ .../types/guide_activate_response.py | 2 + .../types/guide_activation_url_pattern.py | 4 ++ .../guide_activation_url_pattern_param.py | 4 ++ .../types/guide_archive_response.py | 2 + src/knock_mapi/types/guide_step.py | 2 + src/knock_mapi/types/guide_step_param.py | 2 + src/knock_mapi/types/guide_upsert_params.py | 2 + src/knock_mapi/types/guide_upsert_response.py | 2 + src/knock_mapi/types/guide_validate_params.py | 2 + .../types/guide_validate_response.py | 2 + .../types/in_app_feed_channel_settings.py | 5 +++ .../in_app_feed_channel_settings_param.py | 5 +++ src/knock_mapi/types/in_app_feed_template.py | 4 ++ .../types/in_app_feed_template_param.py | 4 ++ src/knock_mapi/types/message_type.py | 4 ++ .../types/message_type_text_field.py | 4 ++ .../types/message_type_text_field_param.py | 4 ++ .../types/message_type_upsert_params.py | 2 + .../types/message_type_upsert_response.py | 2 + .../types/message_type_validate_params.py | 2 + .../types/message_type_validate_response.py | 2 + src/knock_mapi/types/message_type_variant.py | 38 +++++++++++++++++++ .../types/message_type_variant_param.py | 38 +++++++++++++++++++ src/knock_mapi/types/partial.py | 2 + src/knock_mapi/types/partial_upsert_params.py | 2 + .../types/partial_upsert_response.py | 2 + .../types/partial_validate_params.py | 2 + .../types/partial_validate_response.py | 2 + src/knock_mapi/types/push_channel_settings.py | 5 +++ .../types/push_channel_settings_param.py | 5 +++ src/knock_mapi/types/push_template.py | 6 +++ src/knock_mapi/types/push_template_param.py | 6 +++ src/knock_mapi/types/request_template.py | 2 + .../types/request_template_param.py | 2 + src/knock_mapi/types/send_window.py | 2 + src/knock_mapi/types/send_window_param.py | 2 + src/knock_mapi/types/shared/page_info.py | 2 + src/knock_mapi/types/sms_channel_settings.py | 5 +++ .../types/sms_channel_settings_param.py | 5 +++ src/knock_mapi/types/sms_template.py | 6 +++ src/knock_mapi/types/sms_template_param.py | 6 +++ src/knock_mapi/types/translation.py | 2 + .../types/translation_retrieve_response.py | 2 + .../types/translation_upsert_params.py | 4 ++ .../types/translation_upsert_response.py | 2 + .../types/translation_validate_params.py | 4 ++ .../types/translation_validate_response.py | 2 + src/knock_mapi/types/variable.py | 2 + src/knock_mapi/types/webhook_template.py | 5 +++ .../types/webhook_template_param.py | 5 +++ src/knock_mapi/types/workflow.py | 4 ++ .../types/workflow_activate_response.py | 2 + src/knock_mapi/types/workflow_batch_step.py | 7 ++++ .../types/workflow_batch_step_param.py | 7 ++++ src/knock_mapi/types/workflow_branch_step.py | 7 ++++ .../types/workflow_branch_step_param.py | 7 ++++ src/knock_mapi/types/workflow_chat_step.py | 5 +++ .../types/workflow_chat_step_param.py | 5 +++ src/knock_mapi/types/workflow_delay_step.py | 10 +++++ .../types/workflow_delay_step_param.py | 10 +++++ src/knock_mapi/types/workflow_email_step.py | 5 +++ .../types/workflow_email_step_param.py | 5 +++ src/knock_mapi/types/workflow_fetch_step.py | 5 +++ .../types/workflow_fetch_step_param.py | 5 +++ .../types/workflow_in_app_feed_step.py | 5 +++ .../types/workflow_in_app_feed_step_param.py | 5 +++ src/knock_mapi/types/workflow_push_step.py | 5 +++ .../types/workflow_push_step_param.py | 5 +++ .../types/workflow_retrieve_response.py | 8 ++++ src/knock_mapi/types/workflow_run_params.py | 4 ++ src/knock_mapi/types/workflow_run_response.py | 2 + src/knock_mapi/types/workflow_sms_step.py | 5 +++ .../types/workflow_sms_step_param.py | 5 +++ .../types/workflow_throttle_step.py | 7 ++++ .../types/workflow_throttle_step_param.py | 7 ++++ .../types/workflow_trigger_workflow_step.py | 7 ++++ .../workflow_trigger_workflow_step_param.py | 7 ++++ .../types/workflow_upsert_params.py | 4 ++ .../types/workflow_upsert_response.py | 2 + .../types/workflow_validate_params.py | 4 ++ .../types/workflow_validate_response.py | 2 + src/knock_mapi/types/workflow_webhook_step.py | 5 +++ .../types/workflow_webhook_step_param.py | 5 +++ .../workflows/step_preview_template_params.py | 4 ++ .../step_preview_template_response.py | 2 + 122 files changed, 594 insertions(+) diff --git a/src/knock_mapi/types/api_key_exchange_response.py b/src/knock_mapi/types/api_key_exchange_response.py index 73f229f..1db31e0 100644 --- a/src/knock_mapi/types/api_key_exchange_response.py +++ b/src/knock_mapi/types/api_key_exchange_response.py @@ -6,5 +6,7 @@ class APIKeyExchangeResponse(BaseModel): + """Returns an API key that can be used to make requests to the public API.""" + api_key: str """The secret API key exchanged from the service token.""" diff --git a/src/knock_mapi/types/auth_verify_response.py b/src/knock_mapi/types/auth_verify_response.py index 4f67ec3..36c691b 100644 --- a/src/knock_mapi/types/auth_verify_response.py +++ b/src/knock_mapi/types/auth_verify_response.py @@ -9,6 +9,8 @@ class AccountFeatures(BaseModel): + """Account plan features and limits.""" + batch_items_render_limit_allowed: Optional[bool] = None """Whether batch rendering limits can be configured.""" @@ -65,6 +67,8 @@ class AccountFeatures(BaseModel): class AuthVerifyResponse(BaseModel): + """Information about the current calling scope.""" + account_features: AccountFeatures """Account plan features and limits.""" diff --git a/src/knock_mapi/types/branch.py b/src/knock_mapi/types/branch.py index 2131be1..b79bb5f 100644 --- a/src/knock_mapi/types/branch.py +++ b/src/knock_mapi/types/branch.py @@ -9,6 +9,8 @@ class Branch(BaseModel): + """A branch object.""" + created_at: datetime """The timestamp of when the branch was created.""" diff --git a/src/knock_mapi/types/broadcast.py b/src/knock_mapi/types/broadcast.py index 05ef994..18a986b 100644 --- a/src/knock_mapi/types/broadcast.py +++ b/src/knock_mapi/types/broadcast.py @@ -30,6 +30,8 @@ class Settings(BaseModel): + """A map of broadcast settings.""" + is_commercial: Optional[bool] = None """Whether the broadcast is commercial. Defaults to true.""" @@ -42,6 +44,8 @@ class Settings(BaseModel): class Broadcast(BaseModel): + """A broadcast object.""" + created_at: datetime """The timestamp of when the broadcast was created. (read-only).""" diff --git a/src/knock_mapi/types/broadcast_cancel_response.py b/src/knock_mapi/types/broadcast_cancel_response.py index a96d07b..9bd2565 100644 --- a/src/knock_mapi/types/broadcast_cancel_response.py +++ b/src/knock_mapi/types/broadcast_cancel_response.py @@ -8,6 +8,8 @@ class BroadcastCancelResponse(BaseModel): + """Wraps the Broadcast response under the `broadcast` key.""" + broadcast: "Broadcast" """A broadcast object.""" diff --git a/src/knock_mapi/types/broadcast_request_param.py b/src/knock_mapi/types/broadcast_request_param.py index 0a981a5..37a076c 100644 --- a/src/knock_mapi/types/broadcast_request_param.py +++ b/src/knock_mapi/types/broadcast_request_param.py @@ -31,6 +31,8 @@ class Settings(TypedDict, total=False): + """A map of broadcast settings.""" + is_commercial: bool """Whether the broadcast is commercial. Defaults to true.""" @@ -43,6 +45,8 @@ class Settings(TypedDict, total=False): class BroadcastRequestParam(TypedDict, total=False): + """A broadcast request for upserting a broadcast.""" + name: Required[str] """A name for the broadcast. Must be at maximum 255 characters in length.""" diff --git a/src/knock_mapi/types/broadcast_send_response.py b/src/knock_mapi/types/broadcast_send_response.py index 6c21539..03f77ca 100644 --- a/src/knock_mapi/types/broadcast_send_response.py +++ b/src/knock_mapi/types/broadcast_send_response.py @@ -8,6 +8,8 @@ class BroadcastSendResponse(BaseModel): + """Wraps the Broadcast response under the `broadcast` key.""" + broadcast: "Broadcast" """A broadcast object.""" diff --git a/src/knock_mapi/types/broadcast_upsert_response.py b/src/knock_mapi/types/broadcast_upsert_response.py index 0fff352..006457a 100644 --- a/src/knock_mapi/types/broadcast_upsert_response.py +++ b/src/knock_mapi/types/broadcast_upsert_response.py @@ -8,6 +8,8 @@ class BroadcastUpsertResponse(BaseModel): + """Wraps the Broadcast response under the `broadcast` key.""" + broadcast: "Broadcast" """A broadcast object.""" diff --git a/src/knock_mapi/types/broadcast_validate_response.py b/src/knock_mapi/types/broadcast_validate_response.py index b958730..f5a7430 100644 --- a/src/knock_mapi/types/broadcast_validate_response.py +++ b/src/knock_mapi/types/broadcast_validate_response.py @@ -8,6 +8,8 @@ class BroadcastValidateResponse(BaseModel): + """Wraps the Broadcast response under the `broadcast` key.""" + broadcast: "Broadcast" """A broadcast object.""" diff --git a/src/knock_mapi/types/channel.py b/src/knock_mapi/types/channel.py index a9a98d6..87dd516 100644 --- a/src/knock_mapi/types/channel.py +++ b/src/knock_mapi/types/channel.py @@ -10,6 +10,8 @@ class Channel(BaseModel): + """A configured channel, which is a way to route messages to a provider.""" + id: str """The unique identifier for the channel.""" diff --git a/src/knock_mapi/types/channel_group.py b/src/knock_mapi/types/channel_group.py index 1a24290..369ef6f 100644 --- a/src/knock_mapi/types/channel_group.py +++ b/src/knock_mapi/types/channel_group.py @@ -11,6 +11,8 @@ class ChannelGroup(BaseModel): + """A group of channels with rules for when they are applicable.""" + channel_rules: List[ChannelGroupRule] """Rules for determining which channels should be used.""" diff --git a/src/knock_mapi/types/channel_group_rule.py b/src/knock_mapi/types/channel_group_rule.py index aba7941..5968492 100644 --- a/src/knock_mapi/types/channel_group_rule.py +++ b/src/knock_mapi/types/channel_group_rule.py @@ -11,6 +11,10 @@ class ChannelGroupRule(BaseModel): + """ + A rule that determines if a channel should be executed as part of a channel group. + """ + channel: Channel """A configured channel, which is a way to route messages to a provider.""" diff --git a/src/knock_mapi/types/chat_channel_settings.py b/src/knock_mapi/types/chat_channel_settings.py index 09b9d1e..f5c2047 100644 --- a/src/knock_mapi/types/chat_channel_settings.py +++ b/src/knock_mapi/types/chat_channel_settings.py @@ -8,6 +8,11 @@ class ChatChannelSettings(BaseModel): + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + email_based_user_id_resolution: Optional[bool] = None """Whether to resolve chat provider user IDs using a Knock user's email address. diff --git a/src/knock_mapi/types/chat_channel_settings_param.py b/src/knock_mapi/types/chat_channel_settings_param.py index b631453..264c8da 100644 --- a/src/knock_mapi/types/chat_channel_settings_param.py +++ b/src/knock_mapi/types/chat_channel_settings_param.py @@ -8,6 +8,11 @@ class ChatChannelSettingsParam(TypedDict, total=False): + """Chat channel settings. + + Only used as configuration as part of a workflow channel step. + """ + email_based_user_id_resolution: bool """Whether to resolve chat provider user IDs using a Knock user's email address. diff --git a/src/knock_mapi/types/chat_template.py b/src/knock_mapi/types/chat_template.py index e237e15..12ba6fa 100644 --- a/src/knock_mapi/types/chat_template.py +++ b/src/knock_mapi/types/chat_template.py @@ -8,6 +8,8 @@ class ChatTemplate(BaseModel): + """A chat template.""" + markdown_body: str """The markdown body of the chat template.""" diff --git a/src/knock_mapi/types/chat_template_param.py b/src/knock_mapi/types/chat_template_param.py index ed1f1ec..94222a3 100644 --- a/src/knock_mapi/types/chat_template_param.py +++ b/src/knock_mapi/types/chat_template_param.py @@ -9,6 +9,8 @@ class ChatTemplateParam(TypedDict, total=False): + """A chat template.""" + markdown_body: Required[str] """The markdown body of the chat template.""" diff --git a/src/knock_mapi/types/commit.py b/src/knock_mapi/types/commit.py index 7d90567..198db35 100644 --- a/src/knock_mapi/types/commit.py +++ b/src/knock_mapi/types/commit.py @@ -10,6 +10,8 @@ class Author(BaseModel): + """The author of the commit.""" + email: str """The email address of the commit author.""" @@ -18,6 +20,8 @@ class Author(BaseModel): class Resource(BaseModel): + """The resource object associated with the commit.""" + identifier: str """The unique identifier for the resource.""" @@ -26,6 +30,8 @@ class Resource(BaseModel): class Commit(BaseModel): + """A commit is a change to a resource within an environment, made by an author.""" + id: str """The unique identifier for the commit.""" diff --git a/src/knock_mapi/types/commit_commit_all_response.py b/src/knock_mapi/types/commit_commit_all_response.py index 656b04e..a837d95 100644 --- a/src/knock_mapi/types/commit_commit_all_response.py +++ b/src/knock_mapi/types/commit_commit_all_response.py @@ -6,5 +6,7 @@ class CommitCommitAllResponse(BaseModel): + """The response from committing all changes.""" + result: str """The result of the commit operation.""" diff --git a/src/knock_mapi/types/commit_promote_all_response.py b/src/knock_mapi/types/commit_promote_all_response.py index 865d365..2c57c96 100644 --- a/src/knock_mapi/types/commit_promote_all_response.py +++ b/src/knock_mapi/types/commit_promote_all_response.py @@ -6,5 +6,7 @@ class CommitPromoteAllResponse(BaseModel): + """The response from promoting all changes.""" + result: str """The result of the promote operation.""" diff --git a/src/knock_mapi/types/commit_promote_one_response.py b/src/knock_mapi/types/commit_promote_one_response.py index 2c1d921..156412a 100644 --- a/src/knock_mapi/types/commit_promote_one_response.py +++ b/src/knock_mapi/types/commit_promote_one_response.py @@ -7,5 +7,7 @@ class CommitPromoteOneResponse(BaseModel): + """Wraps the Commit response under the `commit` key.""" + commit: Commit """A commit is a change to a resource within an environment, made by an author.""" diff --git a/src/knock_mapi/types/condition.py b/src/knock_mapi/types/condition.py index bc6d571..5294a95 100644 --- a/src/knock_mapi/types/condition.py +++ b/src/knock_mapi/types/condition.py @@ -9,6 +9,8 @@ class Condition(BaseModel): + """A condition to be evaluated.""" + operator: Literal[ "equal_to", "not_equal_to", diff --git a/src/knock_mapi/types/condition_group.py b/src/knock_mapi/types/condition_group.py index 5505a1a..a39665b 100644 --- a/src/knock_mapi/types/condition_group.py +++ b/src/knock_mapi/types/condition_group.py @@ -16,11 +16,15 @@ class ConditionGroupAllMatch(BaseModel): + """A group of conditions that must all be met.""" + all: Optional[List[Condition]] = None """A list of conditions.""" class ConditionGroupAnyMatchAnyConditionGroupAllMatch(BaseModel): + """A group of conditions that must all be met.""" + all: Optional[List[Condition]] = None """A list of conditions.""" @@ -29,6 +33,8 @@ class ConditionGroupAnyMatchAnyConditionGroupAllMatch(BaseModel): class ConditionGroupAnyMatch(BaseModel): + """A group of conditions that any must be met. Can contain nested alls.""" + any: Optional[List[ConditionGroupAnyMatchAny]] = None """An array of conditions or nested condition groups to evaluate.""" diff --git a/src/knock_mapi/types/condition_group_param.py b/src/knock_mapi/types/condition_group_param.py index 0c8e37f..63a4197 100644 --- a/src/knock_mapi/types/condition_group_param.py +++ b/src/knock_mapi/types/condition_group_param.py @@ -17,11 +17,15 @@ class ConditionGroupAllMatch(TypedDict, total=False): + """A group of conditions that must all be met.""" + all: Iterable[ConditionParam] """A list of conditions.""" class ConditionGroupAnyMatchAnyConditionGroupAllMatch(TypedDict, total=False): + """A group of conditions that must all be met.""" + all: Iterable[ConditionParam] """A list of conditions.""" @@ -30,6 +34,8 @@ class ConditionGroupAnyMatchAnyConditionGroupAllMatch(TypedDict, total=False): class ConditionGroupAnyMatch(TypedDict, total=False): + """A group of conditions that any must be met. Can contain nested alls.""" + any: Iterable[ConditionGroupAnyMatchAny] """An array of conditions or nested condition groups to evaluate.""" diff --git a/src/knock_mapi/types/condition_param.py b/src/knock_mapi/types/condition_param.py index db65a04..452eed6 100644 --- a/src/knock_mapi/types/condition_param.py +++ b/src/knock_mapi/types/condition_param.py @@ -9,6 +9,8 @@ class ConditionParam(TypedDict, total=False): + """A condition to be evaluated.""" + operator: Required[ Literal[ "equal_to", diff --git a/src/knock_mapi/types/duration.py b/src/knock_mapi/types/duration.py index 0d4cbf4..66eda89 100644 --- a/src/knock_mapi/types/duration.py +++ b/src/knock_mapi/types/duration.py @@ -8,6 +8,8 @@ class Duration(BaseModel): + """A duration of time, represented as a unit and a value.""" + unit: Literal["minutes", "hours", "days", "weeks", "months"] """The unit of time.""" diff --git a/src/knock_mapi/types/duration_param.py b/src/knock_mapi/types/duration_param.py index 0fde3d8..e48f044 100644 --- a/src/knock_mapi/types/duration_param.py +++ b/src/knock_mapi/types/duration_param.py @@ -8,6 +8,8 @@ class DurationParam(TypedDict, total=False): + """A duration of time, represented as a unit and a value.""" + unit: Required[Literal["minutes", "hours", "days", "weeks", "months"]] """The unit of time.""" diff --git a/src/knock_mapi/types/email_channel_settings.py b/src/knock_mapi/types/email_channel_settings.py index 89d76b0..a9ea988 100644 --- a/src/knock_mapi/types/email_channel_settings.py +++ b/src/knock_mapi/types/email_channel_settings.py @@ -8,6 +8,11 @@ class EmailChannelSettings(BaseModel): + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + bcc_address: Optional[str] = None """The BCC address on email notifications. Supports liquid.""" diff --git a/src/knock_mapi/types/email_channel_settings_param.py b/src/knock_mapi/types/email_channel_settings_param.py index 93e36e6..5cac215 100644 --- a/src/knock_mapi/types/email_channel_settings_param.py +++ b/src/knock_mapi/types/email_channel_settings_param.py @@ -9,6 +9,11 @@ class EmailChannelSettingsParam(TypedDict, total=False): + """Email channel settings. + + Only used as configuration as part of a workflow channel step. + """ + bcc_address: Optional[str] """The BCC address on email notifications. Supports liquid.""" diff --git a/src/knock_mapi/types/email_layout.py b/src/knock_mapi/types/email_layout.py index a03ec57..27f0f6e 100644 --- a/src/knock_mapi/types/email_layout.py +++ b/src/knock_mapi/types/email_layout.py @@ -17,6 +17,8 @@ class FooterLink(BaseModel): class EmailLayout(BaseModel): + """A versioned email layout used within an environment.""" + created_at: datetime """The timestamp of when the email layout was created.""" diff --git a/src/knock_mapi/types/email_layout_upsert_params.py b/src/knock_mapi/types/email_layout_upsert_params.py index 2a02405..09a5eee 100644 --- a/src/knock_mapi/types/email_layout_upsert_params.py +++ b/src/knock_mapi/types/email_layout_upsert_params.py @@ -40,6 +40,8 @@ class EmailLayoutFooterLink(TypedDict, total=False): class EmailLayout(TypedDict, total=False): + """A request to update or create an email layout.""" + html_layout: Required[str] """The complete HTML content of the email layout.""" diff --git a/src/knock_mapi/types/email_layout_upsert_response.py b/src/knock_mapi/types/email_layout_upsert_response.py index 186f4bb..b1b3e92 100644 --- a/src/knock_mapi/types/email_layout_upsert_response.py +++ b/src/knock_mapi/types/email_layout_upsert_response.py @@ -7,5 +7,7 @@ class EmailLayoutUpsertResponse(BaseModel): + """Wraps the EmailLayout response under the `email_layout` key.""" + email_layout: EmailLayout """A versioned email layout used within an environment.""" diff --git a/src/knock_mapi/types/email_layout_validate_params.py b/src/knock_mapi/types/email_layout_validate_params.py index bf36504..c15d316 100644 --- a/src/knock_mapi/types/email_layout_validate_params.py +++ b/src/knock_mapi/types/email_layout_validate_params.py @@ -31,6 +31,8 @@ class EmailLayoutFooterLink(TypedDict, total=False): class EmailLayout(TypedDict, total=False): + """A request to update or create an email layout.""" + html_layout: Required[str] """The complete HTML content of the email layout.""" diff --git a/src/knock_mapi/types/email_layout_validate_response.py b/src/knock_mapi/types/email_layout_validate_response.py index 28d1a29..adb3501 100644 --- a/src/knock_mapi/types/email_layout_validate_response.py +++ b/src/knock_mapi/types/email_layout_validate_response.py @@ -7,5 +7,7 @@ class EmailLayoutValidateResponse(BaseModel): + """Wraps the EmailLayout response under the `email_layout` key.""" + email_layout: EmailLayout """A versioned email layout used within an environment.""" diff --git a/src/knock_mapi/types/email_template.py b/src/knock_mapi/types/email_template.py index 86b2ac5..01012c7 100644 --- a/src/knock_mapi/types/email_template.py +++ b/src/knock_mapi/types/email_template.py @@ -28,6 +28,10 @@ class Settings(BaseModel): + """ + The [settings](https://docs.knock.app/integrations/email/settings) for the email template. + """ + attachment_key: Optional[str] = None """ The object path in the data payload (of the workflow trigger call) to resolve @@ -45,6 +49,8 @@ class Settings(BaseModel): class VisualBlockEmailButtonSetBlockButtonSizeAttrs(BaseModel): + """The size attributes of the button.""" + is_fullwidth: Optional[bool] = None """Whether the button is full width.""" @@ -53,6 +59,8 @@ class VisualBlockEmailButtonSetBlockButtonSizeAttrs(BaseModel): class VisualBlockEmailButtonSetBlockButtonStyleAttrs(BaseModel): + """The style attributes of the button.""" + background_color: Optional[str] = None """The background color of the button.""" @@ -70,6 +78,8 @@ class VisualBlockEmailButtonSetBlockButtonStyleAttrs(BaseModel): class VisualBlockEmailButtonSetBlockButton(BaseModel): + """A button in a button set block.""" + action: str """The action of the button.""" @@ -87,6 +97,8 @@ class VisualBlockEmailButtonSetBlockButton(BaseModel): class VisualBlockEmailButtonSetBlockLayoutAttrs(BaseModel): + """The layout attributes of the block.""" + column_gap: int """The column_gap layout attribute of the block.""" @@ -107,6 +119,8 @@ class VisualBlockEmailButtonSetBlockLayoutAttrs(BaseModel): class VisualBlockEmailButtonSetBlock(BaseModel): + """A button set block in an email template.""" + id: str """The ID of the block.""" @@ -124,6 +138,8 @@ class VisualBlockEmailButtonSetBlock(BaseModel): class VisualBlockEmailDividerBlockLayoutAttrs(BaseModel): + """The layout attributes of the block.""" + padding_bottom: int """The padding_bottom layout attribute of the block.""" @@ -138,6 +154,8 @@ class VisualBlockEmailDividerBlockLayoutAttrs(BaseModel): class VisualBlockEmailDividerBlock(BaseModel): + """A divider block in an email template.""" + id: str """The ID of the block.""" @@ -152,6 +170,8 @@ class VisualBlockEmailDividerBlock(BaseModel): class VisualBlockEmailHTMLBlock(BaseModel): + """An HTML block in an email template.""" + id: str """The ID of the block.""" @@ -166,6 +186,8 @@ class VisualBlockEmailHTMLBlock(BaseModel): class VisualBlockEmailImageBlockLayoutAttrs(BaseModel): + """The layout attributes of the block.""" + horizontal_align: Literal["left", "center", "right"] """The horizontal alignment of the block.""" @@ -183,11 +205,15 @@ class VisualBlockEmailImageBlockLayoutAttrs(BaseModel): class VisualBlockEmailImageBlockStyleAttrs(BaseModel): + """The style attributes of the image.""" + width: Optional[str] = None """The width of the image.""" class VisualBlockEmailImageBlock(BaseModel): + """An image block in an email template.""" + id: str """The ID of the block.""" @@ -214,6 +240,8 @@ class VisualBlockEmailImageBlock(BaseModel): class VisualBlockEmailMarkdownBlockLayoutAttrs(BaseModel): + """The layout attributes of the block.""" + padding_bottom: int """The padding_bottom layout attribute of the block.""" @@ -228,6 +256,8 @@ class VisualBlockEmailMarkdownBlockLayoutAttrs(BaseModel): class VisualBlockEmailMarkdownBlock(BaseModel): + """A markdown block in an email template.""" + id: str """The ID of the block.""" @@ -248,6 +278,8 @@ class VisualBlockEmailMarkdownBlock(BaseModel): class VisualBlockEmailPartialBlockLayoutAttrs(BaseModel): + """The layout attributes of the block.""" + padding_bottom: int """The padding_bottom layout attribute of the block.""" @@ -262,6 +294,10 @@ class VisualBlockEmailPartialBlockLayoutAttrs(BaseModel): class VisualBlockEmailPartialBlock(BaseModel): + """ + A partial block in an email template, used to render a reusable partial component. + """ + id: str """The ID of the block.""" @@ -295,6 +331,8 @@ class VisualBlockEmailPartialBlock(BaseModel): class EmailTemplate(BaseModel): + """An email message template.""" + subject: str """The subject of the email.""" diff --git a/src/knock_mapi/types/email_template_param.py b/src/knock_mapi/types/email_template_param.py index 5170b52..ab333e7 100644 --- a/src/knock_mapi/types/email_template_param.py +++ b/src/knock_mapi/types/email_template_param.py @@ -28,6 +28,10 @@ class Settings(TypedDict, total=False): + """ + The [settings](https://docs.knock.app/integrations/email/settings) for the email template. + """ + attachment_key: Optional[str] """ The object path in the data payload (of the workflow trigger call) to resolve @@ -45,6 +49,8 @@ class Settings(TypedDict, total=False): class VisualBlockEmailButtonSetBlockButtonSizeAttrs(TypedDict, total=False): + """The size attributes of the button.""" + is_fullwidth: bool """Whether the button is full width.""" @@ -53,6 +59,8 @@ class VisualBlockEmailButtonSetBlockButtonSizeAttrs(TypedDict, total=False): class VisualBlockEmailButtonSetBlockButtonStyleAttrs(TypedDict, total=False): + """The style attributes of the button.""" + background_color: str """The background color of the button.""" @@ -70,6 +78,8 @@ class VisualBlockEmailButtonSetBlockButtonStyleAttrs(TypedDict, total=False): class VisualBlockEmailButtonSetBlockButton(TypedDict, total=False): + """A button in a button set block.""" + action: Required[str] """The action of the button.""" @@ -87,6 +97,8 @@ class VisualBlockEmailButtonSetBlockButton(TypedDict, total=False): class VisualBlockEmailButtonSetBlockLayoutAttrs(TypedDict, total=False): + """The layout attributes of the block.""" + column_gap: Required[int] """The column_gap layout attribute of the block.""" @@ -107,6 +119,8 @@ class VisualBlockEmailButtonSetBlockLayoutAttrs(TypedDict, total=False): class VisualBlockEmailButtonSetBlock(TypedDict, total=False): + """A button set block in an email template.""" + id: Required[str] """The ID of the block.""" @@ -124,6 +138,8 @@ class VisualBlockEmailButtonSetBlock(TypedDict, total=False): class VisualBlockEmailDividerBlockLayoutAttrs(TypedDict, total=False): + """The layout attributes of the block.""" + padding_bottom: Required[int] """The padding_bottom layout attribute of the block.""" @@ -138,6 +154,8 @@ class VisualBlockEmailDividerBlockLayoutAttrs(TypedDict, total=False): class VisualBlockEmailDividerBlock(TypedDict, total=False): + """A divider block in an email template.""" + id: Required[str] """The ID of the block.""" @@ -152,6 +170,8 @@ class VisualBlockEmailDividerBlock(TypedDict, total=False): class VisualBlockEmailHTMLBlock(TypedDict, total=False): + """An HTML block in an email template.""" + id: Required[str] """The ID of the block.""" @@ -166,6 +186,8 @@ class VisualBlockEmailHTMLBlock(TypedDict, total=False): class VisualBlockEmailImageBlockLayoutAttrs(TypedDict, total=False): + """The layout attributes of the block.""" + horizontal_align: Required[Literal["left", "center", "right"]] """The horizontal alignment of the block.""" @@ -183,11 +205,15 @@ class VisualBlockEmailImageBlockLayoutAttrs(TypedDict, total=False): class VisualBlockEmailImageBlockStyleAttrs(TypedDict, total=False): + """The style attributes of the image.""" + width: str """The width of the image.""" class VisualBlockEmailImageBlock(TypedDict, total=False): + """An image block in an email template.""" + id: Required[str] """The ID of the block.""" @@ -214,6 +240,8 @@ class VisualBlockEmailImageBlock(TypedDict, total=False): class VisualBlockEmailMarkdownBlockLayoutAttrs(TypedDict, total=False): + """The layout attributes of the block.""" + padding_bottom: Required[int] """The padding_bottom layout attribute of the block.""" @@ -228,6 +256,8 @@ class VisualBlockEmailMarkdownBlockLayoutAttrs(TypedDict, total=False): class VisualBlockEmailMarkdownBlock(TypedDict, total=False): + """A markdown block in an email template.""" + id: Required[str] """The ID of the block.""" @@ -248,6 +278,8 @@ class VisualBlockEmailMarkdownBlock(TypedDict, total=False): class VisualBlockEmailPartialBlockLayoutAttrs(TypedDict, total=False): + """The layout attributes of the block.""" + padding_bottom: Required[int] """The padding_bottom layout attribute of the block.""" @@ -262,6 +294,10 @@ class VisualBlockEmailPartialBlockLayoutAttrs(TypedDict, total=False): class VisualBlockEmailPartialBlock(TypedDict, total=False): + """ + A partial block in an email template, used to render a reusable partial component. + """ + id: Required[str] """The ID of the block.""" @@ -295,6 +331,8 @@ class VisualBlockEmailPartialBlock(TypedDict, total=False): class EmailTemplateParam(TypedDict, total=False): + """An email message template.""" + subject: Required[str] """The subject of the email.""" diff --git a/src/knock_mapi/types/environment.py b/src/knock_mapi/types/environment.py index 0fac90e..5646e4b 100644 --- a/src/knock_mapi/types/environment.py +++ b/src/knock_mapi/types/environment.py @@ -10,6 +10,8 @@ class Environment(BaseModel): + """An environment object.""" + created_at: datetime """The timestamp of when the environment was created.""" diff --git a/src/knock_mapi/types/guide.py b/src/knock_mapi/types/guide.py index 5d639bc..1924926 100644 --- a/src/knock_mapi/types/guide.py +++ b/src/knock_mapi/types/guide.py @@ -12,6 +12,10 @@ class Guide(BaseModel): + """ + A guide defines an in-app guide that can be displayed to users based on priority and other conditions. + """ + active: bool """Whether the guide is active.""" diff --git a/src/knock_mapi/types/guide_activate_response.py b/src/knock_mapi/types/guide_activate_response.py index 2055f16..fbf25fc 100644 --- a/src/knock_mapi/types/guide_activate_response.py +++ b/src/knock_mapi/types/guide_activate_response.py @@ -7,6 +7,8 @@ class GuideActivateResponse(BaseModel): + """Wraps the Guide response under the `guide` key.""" + guide: Guide """ A guide defines an in-app guide that can be displayed to users based on priority diff --git a/src/knock_mapi/types/guide_activation_url_pattern.py b/src/knock_mapi/types/guide_activation_url_pattern.py index 8342450..b28b672 100644 --- a/src/knock_mapi/types/guide_activation_url_pattern.py +++ b/src/knock_mapi/types/guide_activation_url_pattern.py @@ -8,6 +8,10 @@ class GuideActivationURLPattern(BaseModel): + """ + A rule that controls when a guide should be shown based on the user's location in the application. + """ + directive: Literal["allow", "block"] """Whether to allow or block the guide at the specified pathname.""" diff --git a/src/knock_mapi/types/guide_activation_url_pattern_param.py b/src/knock_mapi/types/guide_activation_url_pattern_param.py index 52d4a9f..b5c4e74 100644 --- a/src/knock_mapi/types/guide_activation_url_pattern_param.py +++ b/src/knock_mapi/types/guide_activation_url_pattern_param.py @@ -8,6 +8,10 @@ class GuideActivationURLPatternParam(TypedDict, total=False): + """ + A rule that controls when a guide should be shown based on the user's location in the application. + """ + directive: Required[Literal["allow", "block"]] """Whether to allow or block the guide at the specified pathname.""" diff --git a/src/knock_mapi/types/guide_archive_response.py b/src/knock_mapi/types/guide_archive_response.py index 41a14a6..e930e19 100644 --- a/src/knock_mapi/types/guide_archive_response.py +++ b/src/knock_mapi/types/guide_archive_response.py @@ -6,5 +6,7 @@ class GuideArchiveResponse(BaseModel): + """The response from archiving a guide.""" + result: str """The result of the promote operation.""" diff --git a/src/knock_mapi/types/guide_step.py b/src/knock_mapi/types/guide_step.py index 00fdd38..6143cb4 100644 --- a/src/knock_mapi/types/guide_step.py +++ b/src/knock_mapi/types/guide_step.py @@ -8,6 +8,8 @@ class GuideStep(BaseModel): + """A step in a guide that corresponds to a piece of UI and its content.""" + ref: str """The unique reference string for the step. diff --git a/src/knock_mapi/types/guide_step_param.py b/src/knock_mapi/types/guide_step_param.py index bac89bc..e202de9 100644 --- a/src/knock_mapi/types/guide_step_param.py +++ b/src/knock_mapi/types/guide_step_param.py @@ -9,6 +9,8 @@ class GuideStepParam(TypedDict, total=False): + """A step in a guide that corresponds to a piece of UI and its content.""" + ref: Required[str] """The unique reference string for the step. diff --git a/src/knock_mapi/types/guide_upsert_params.py b/src/knock_mapi/types/guide_upsert_params.py index 146661e..fe79da0 100644 --- a/src/knock_mapi/types/guide_upsert_params.py +++ b/src/knock_mapi/types/guide_upsert_params.py @@ -38,6 +38,8 @@ class GuideUpsertParams(TypedDict, total=False): class Guide(TypedDict, total=False): + """A request to create or update a guide.""" + channel_key: Required[str] """The key of the channel in which the guide exists.""" diff --git a/src/knock_mapi/types/guide_upsert_response.py b/src/knock_mapi/types/guide_upsert_response.py index f554cd8..8c2957b 100644 --- a/src/knock_mapi/types/guide_upsert_response.py +++ b/src/knock_mapi/types/guide_upsert_response.py @@ -7,6 +7,8 @@ class GuideUpsertResponse(BaseModel): + """Wraps the Guide response under the `guide` key.""" + guide: Guide """ A guide defines an in-app guide that can be displayed to users based on priority diff --git a/src/knock_mapi/types/guide_validate_params.py b/src/knock_mapi/types/guide_validate_params.py index aeaee81..77b2ab8 100644 --- a/src/knock_mapi/types/guide_validate_params.py +++ b/src/knock_mapi/types/guide_validate_params.py @@ -29,6 +29,8 @@ class GuideValidateParams(TypedDict, total=False): class Guide(TypedDict, total=False): + """A request to create or update a guide.""" + channel_key: Required[str] """The key of the channel in which the guide exists.""" diff --git a/src/knock_mapi/types/guide_validate_response.py b/src/knock_mapi/types/guide_validate_response.py index 85ff92a..0ee351a 100644 --- a/src/knock_mapi/types/guide_validate_response.py +++ b/src/knock_mapi/types/guide_validate_response.py @@ -7,6 +7,8 @@ class GuideValidateResponse(BaseModel): + """Wraps the Guide response under the `guide` key.""" + guide: Guide """ A guide defines an in-app guide that can be displayed to users based on priority diff --git a/src/knock_mapi/types/in_app_feed_channel_settings.py b/src/knock_mapi/types/in_app_feed_channel_settings.py index a6c9923..21022b2 100644 --- a/src/knock_mapi/types/in_app_feed_channel_settings.py +++ b/src/knock_mapi/types/in_app_feed_channel_settings.py @@ -8,5 +8,10 @@ class InAppFeedChannelSettings(BaseModel): + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + link_tracking: Optional[bool] = None """Whether to track link clicks on in-app feed notifications.""" diff --git a/src/knock_mapi/types/in_app_feed_channel_settings_param.py b/src/knock_mapi/types/in_app_feed_channel_settings_param.py index f674cbc..0a300f0 100644 --- a/src/knock_mapi/types/in_app_feed_channel_settings_param.py +++ b/src/knock_mapi/types/in_app_feed_channel_settings_param.py @@ -8,5 +8,10 @@ class InAppFeedChannelSettingsParam(TypedDict, total=False): + """In-app feed channel settings. + + Only used as configuration as part of a workflow channel step. + """ + link_tracking: bool """Whether to track link clicks on in-app feed notifications.""" diff --git a/src/knock_mapi/types/in_app_feed_template.py b/src/knock_mapi/types/in_app_feed_template.py index 55a23de..94b6069 100644 --- a/src/knock_mapi/types/in_app_feed_template.py +++ b/src/knock_mapi/types/in_app_feed_template.py @@ -8,6 +8,8 @@ class ActionButton(BaseModel): + """A single-action button to be rendered in an in-app feed cell.""" + action: str """The URI for this action.""" @@ -16,6 +18,8 @@ class ActionButton(BaseModel): class InAppFeedTemplate(BaseModel): + """An in-app feed template.""" + markdown_body: str """The markdown body of the in-app feed.""" diff --git a/src/knock_mapi/types/in_app_feed_template_param.py b/src/knock_mapi/types/in_app_feed_template_param.py index bf017f1..6ec2fd1 100644 --- a/src/knock_mapi/types/in_app_feed_template_param.py +++ b/src/knock_mapi/types/in_app_feed_template_param.py @@ -9,6 +9,8 @@ class ActionButton(TypedDict, total=False): + """A single-action button to be rendered in an in-app feed cell.""" + action: Required[str] """The URI for this action.""" @@ -17,6 +19,8 @@ class ActionButton(TypedDict, total=False): class InAppFeedTemplateParam(TypedDict, total=False): + """An in-app feed template.""" + markdown_body: Required[str] """The markdown body of the in-app feed.""" diff --git a/src/knock_mapi/types/message_type.py b/src/knock_mapi/types/message_type.py index 05dd65b..538aae8 100644 --- a/src/knock_mapi/types/message_type.py +++ b/src/knock_mapi/types/message_type.py @@ -11,6 +11,10 @@ class MessageType(BaseModel): + """ + A message type is a schema for a message that maps to a UI component or element within your application. + """ + created_at: datetime """The timestamp of when the message type was created.""" diff --git a/src/knock_mapi/types/message_type_text_field.py b/src/knock_mapi/types/message_type_text_field.py index 4ff018e..018f2fe 100644 --- a/src/knock_mapi/types/message_type_text_field.py +++ b/src/knock_mapi/types/message_type_text_field.py @@ -9,6 +9,8 @@ class Settings(BaseModel): + """Settings for the text field.""" + default: Optional[str] = None """The default value of the text field.""" @@ -23,6 +25,8 @@ class Settings(BaseModel): class MessageTypeTextField(BaseModel): + """A text field used in a message type.""" + key: str """The unique key of the field.""" diff --git a/src/knock_mapi/types/message_type_text_field_param.py b/src/knock_mapi/types/message_type_text_field_param.py index 25fd777..556a795 100644 --- a/src/knock_mapi/types/message_type_text_field_param.py +++ b/src/knock_mapi/types/message_type_text_field_param.py @@ -9,6 +9,8 @@ class Settings(TypedDict, total=False): + """Settings for the text field.""" + default: Optional[str] """The default value of the text field.""" @@ -23,6 +25,8 @@ class Settings(TypedDict, total=False): class MessageTypeTextFieldParam(TypedDict, total=False): + """A text field used in a message type.""" + key: Required[str] """The unique key of the field.""" diff --git a/src/knock_mapi/types/message_type_upsert_params.py b/src/knock_mapi/types/message_type_upsert_params.py index 4fbce07..3b3fc07 100644 --- a/src/knock_mapi/types/message_type_upsert_params.py +++ b/src/knock_mapi/types/message_type_upsert_params.py @@ -34,6 +34,8 @@ class MessageTypeUpsertParams(TypedDict, total=False): class MessageType(TypedDict, total=False): + """A request to create a message type.""" + description: Required[Optional[str]] """An arbitrary string attached to a message type object. diff --git a/src/knock_mapi/types/message_type_upsert_response.py b/src/knock_mapi/types/message_type_upsert_response.py index 3c77505..d93e1dc 100644 --- a/src/knock_mapi/types/message_type_upsert_response.py +++ b/src/knock_mapi/types/message_type_upsert_response.py @@ -7,6 +7,8 @@ class MessageTypeUpsertResponse(BaseModel): + """Wraps the MessageType response under the `message_type` key.""" + message_type: MessageType """ A message type is a schema for a message that maps to a UI component or element diff --git a/src/knock_mapi/types/message_type_validate_params.py b/src/knock_mapi/types/message_type_validate_params.py index 288a216..6574f8d 100644 --- a/src/knock_mapi/types/message_type_validate_params.py +++ b/src/knock_mapi/types/message_type_validate_params.py @@ -25,6 +25,8 @@ class MessageTypeValidateParams(TypedDict, total=False): class MessageType(TypedDict, total=False): + """A request to create a message type.""" + description: Required[Optional[str]] """An arbitrary string attached to a message type object. diff --git a/src/knock_mapi/types/message_type_validate_response.py b/src/knock_mapi/types/message_type_validate_response.py index d1ff302..a7f5f39 100644 --- a/src/knock_mapi/types/message_type_validate_response.py +++ b/src/knock_mapi/types/message_type_validate_response.py @@ -7,6 +7,8 @@ class MessageTypeValidateResponse(BaseModel): + """Wraps the MessageType response under the `message_type` key.""" + message_type: MessageType """ A message type is a schema for a message that maps to a UI component or element diff --git a/src/knock_mapi/types/message_type_variant.py b/src/knock_mapi/types/message_type_variant.py index 2c69539..d8d03c7 100644 --- a/src/knock_mapi/types/message_type_variant.py +++ b/src/knock_mapi/types/message_type_variant.py @@ -33,6 +33,8 @@ class FieldMessageTypeBooleanFieldSettings(BaseModel): + """Settings for the boolean field.""" + default: Optional[bool] = None """The default value of the boolean field.""" @@ -43,6 +45,8 @@ class FieldMessageTypeBooleanFieldSettings(BaseModel): class FieldMessageTypeBooleanField(BaseModel): + """A boolean field used in a message type.""" + key: str """The unique key of the field.""" @@ -57,6 +61,8 @@ class FieldMessageTypeBooleanField(BaseModel): class FieldMessageTypeButtonFieldSettings(BaseModel): + """Settings for the button field.""" + description: Optional[str] = None required: Optional[bool] = None @@ -64,6 +70,8 @@ class FieldMessageTypeButtonFieldSettings(BaseModel): class FieldMessageTypeButtonField(BaseModel): + """A button field used in a message type.""" + action: MessageTypeTextField """A text field used in a message type.""" @@ -84,6 +92,8 @@ class FieldMessageTypeButtonField(BaseModel): class FieldMessageTypeImageFieldURLSettings(BaseModel): + """Settings for the url field.""" + default: Optional[str] = None """The default value of the URL field.""" @@ -94,6 +104,8 @@ class FieldMessageTypeImageFieldURLSettings(BaseModel): class FieldMessageTypeImageFieldURL(BaseModel): + """A URL field used in a message type.""" + key: str """The unique key of the field.""" @@ -108,6 +120,8 @@ class FieldMessageTypeImageFieldURL(BaseModel): class FieldMessageTypeImageFieldSettings(BaseModel): + """Settings for the image field.""" + description: Optional[str] = None required: Optional[bool] = None @@ -115,6 +129,8 @@ class FieldMessageTypeImageFieldSettings(BaseModel): class FieldMessageTypeImageField(BaseModel): + """An image field used in a message type.""" + action: MessageTypeTextField """A text field used in a message type.""" @@ -138,6 +154,8 @@ class FieldMessageTypeImageField(BaseModel): class FieldMessageTypeMarkdownFieldSettings(BaseModel): + """Settings for the markdown field.""" + default: Optional[str] = None """The default value of the markdown field.""" @@ -148,6 +166,8 @@ class FieldMessageTypeMarkdownFieldSettings(BaseModel): class FieldMessageTypeMarkdownField(BaseModel): + """A markdown field used in a message type.""" + key: str """The unique key of the field.""" @@ -170,6 +190,8 @@ class FieldMessageTypeMultiSelectFieldSettingsOption(BaseModel): class FieldMessageTypeMultiSelectFieldSettings(BaseModel): + """Settings for the multi_select field.""" + default: Optional[List[str]] = None """The default values for the multi-select field.""" @@ -183,6 +205,8 @@ class FieldMessageTypeMultiSelectFieldSettings(BaseModel): class FieldMessageTypeMultiSelectField(BaseModel): + """A multi-select field used in a message type.""" + key: str """The unique key of the field.""" @@ -205,6 +229,8 @@ class FieldMessageTypeSelectFieldSettingsOption(BaseModel): class FieldMessageTypeSelectFieldSettings(BaseModel): + """Settings for the select field.""" + default: Optional[str] = None """The default value for the select field.""" @@ -218,6 +244,8 @@ class FieldMessageTypeSelectFieldSettings(BaseModel): class FieldMessageTypeSelectField(BaseModel): + """A select field used in a message type.""" + key: str """The unique key of the field.""" @@ -232,6 +260,8 @@ class FieldMessageTypeSelectField(BaseModel): class FieldMessageTypeTextareaFieldSettings(BaseModel): + """Settings for the textarea field.""" + default: Optional[str] = None """The default value of the textarea field.""" @@ -246,6 +276,8 @@ class FieldMessageTypeTextareaFieldSettings(BaseModel): class FieldMessageTypeTextareaField(BaseModel): + """A textarea field used in a message type.""" + key: str """The unique key of the field.""" @@ -260,6 +292,8 @@ class FieldMessageTypeTextareaField(BaseModel): class FieldMessageTypeURLFieldSettings(BaseModel): + """Settings for the url field.""" + default: Optional[str] = None """The default value of the URL field.""" @@ -270,6 +304,8 @@ class FieldMessageTypeURLFieldSettings(BaseModel): class FieldMessageTypeURLField(BaseModel): + """A URL field used in a message type.""" + key: str """The unique key of the field.""" @@ -297,6 +333,8 @@ class FieldMessageTypeURLField(BaseModel): class MessageTypeVariant(BaseModel): + """A variant of a message type.""" + fields: List[Field] """The field types available for the variant.""" diff --git a/src/knock_mapi/types/message_type_variant_param.py b/src/knock_mapi/types/message_type_variant_param.py index 4f9d0df..b37c248 100644 --- a/src/knock_mapi/types/message_type_variant_param.py +++ b/src/knock_mapi/types/message_type_variant_param.py @@ -35,6 +35,8 @@ class FieldMessageTypeBooleanFieldSettings(TypedDict, total=False): + """Settings for the boolean field.""" + default: bool """The default value of the boolean field.""" @@ -45,6 +47,8 @@ class FieldMessageTypeBooleanFieldSettings(TypedDict, total=False): class FieldMessageTypeBooleanField(TypedDict, total=False): + """A boolean field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -59,6 +63,8 @@ class FieldMessageTypeBooleanField(TypedDict, total=False): class FieldMessageTypeButtonFieldSettings(TypedDict, total=False): + """Settings for the button field.""" + description: str required: bool @@ -66,6 +72,8 @@ class FieldMessageTypeButtonFieldSettings(TypedDict, total=False): class FieldMessageTypeButtonField(TypedDict, total=False): + """A button field used in a message type.""" + action: Required[MessageTypeTextFieldParam] """A text field used in a message type.""" @@ -86,6 +94,8 @@ class FieldMessageTypeButtonField(TypedDict, total=False): class FieldMessageTypeImageFieldURLSettings(TypedDict, total=False): + """Settings for the url field.""" + default: Optional[str] """The default value of the URL field.""" @@ -96,6 +106,8 @@ class FieldMessageTypeImageFieldURLSettings(TypedDict, total=False): class FieldMessageTypeImageFieldURL(TypedDict, total=False): + """A URL field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -110,6 +122,8 @@ class FieldMessageTypeImageFieldURL(TypedDict, total=False): class FieldMessageTypeImageFieldSettings(TypedDict, total=False): + """Settings for the image field.""" + description: str required: bool @@ -117,6 +131,8 @@ class FieldMessageTypeImageFieldSettings(TypedDict, total=False): class FieldMessageTypeImageField(TypedDict, total=False): + """An image field used in a message type.""" + action: Required[MessageTypeTextFieldParam] """A text field used in a message type.""" @@ -140,6 +156,8 @@ class FieldMessageTypeImageField(TypedDict, total=False): class FieldMessageTypeMarkdownFieldSettings(TypedDict, total=False): + """Settings for the markdown field.""" + default: str """The default value of the markdown field.""" @@ -150,6 +168,8 @@ class FieldMessageTypeMarkdownFieldSettings(TypedDict, total=False): class FieldMessageTypeMarkdownField(TypedDict, total=False): + """A markdown field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -172,6 +192,8 @@ class FieldMessageTypeMultiSelectFieldSettingsOption(TypedDict, total=False): class FieldMessageTypeMultiSelectFieldSettings(TypedDict, total=False): + """Settings for the multi_select field.""" + default: Optional[SequenceNotStr[str]] """The default values for the multi-select field.""" @@ -185,6 +207,8 @@ class FieldMessageTypeMultiSelectFieldSettings(TypedDict, total=False): class FieldMessageTypeMultiSelectField(TypedDict, total=False): + """A multi-select field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -207,6 +231,8 @@ class FieldMessageTypeSelectFieldSettingsOption(TypedDict, total=False): class FieldMessageTypeSelectFieldSettings(TypedDict, total=False): + """Settings for the select field.""" + default: Optional[str] """The default value for the select field.""" @@ -220,6 +246,8 @@ class FieldMessageTypeSelectFieldSettings(TypedDict, total=False): class FieldMessageTypeSelectField(TypedDict, total=False): + """A select field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -234,6 +262,8 @@ class FieldMessageTypeSelectField(TypedDict, total=False): class FieldMessageTypeTextareaFieldSettings(TypedDict, total=False): + """Settings for the textarea field.""" + default: Optional[str] """The default value of the textarea field.""" @@ -248,6 +278,8 @@ class FieldMessageTypeTextareaFieldSettings(TypedDict, total=False): class FieldMessageTypeTextareaField(TypedDict, total=False): + """A textarea field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -262,6 +294,8 @@ class FieldMessageTypeTextareaField(TypedDict, total=False): class FieldMessageTypeURLFieldSettings(TypedDict, total=False): + """Settings for the url field.""" + default: Optional[str] """The default value of the URL field.""" @@ -272,6 +306,8 @@ class FieldMessageTypeURLFieldSettings(TypedDict, total=False): class FieldMessageTypeURLField(TypedDict, total=False): + """A URL field used in a message type.""" + key: Required[str] """The unique key of the field.""" @@ -299,6 +335,8 @@ class FieldMessageTypeURLField(TypedDict, total=False): class MessageTypeVariantParam(TypedDict, total=False): + """A variant of a message type.""" + fields: Required[Iterable[Field]] """The field types available for the variant.""" diff --git a/src/knock_mapi/types/partial.py b/src/knock_mapi/types/partial.py index 16e818f..d269451 100644 --- a/src/knock_mapi/types/partial.py +++ b/src/knock_mapi/types/partial.py @@ -10,6 +10,8 @@ class Partial(BaseModel): + """A partial is a reusable piece of content that can be used in a template.""" + content: str """The partial content.""" diff --git a/src/knock_mapi/types/partial_upsert_params.py b/src/knock_mapi/types/partial_upsert_params.py index b2a9993..00b1875 100644 --- a/src/knock_mapi/types/partial_upsert_params.py +++ b/src/knock_mapi/types/partial_upsert_params.py @@ -32,6 +32,8 @@ class PartialUpsertParams(TypedDict, total=False): class Partial(TypedDict, total=False): + """A partial object with attributes to update or create a partial.""" + content: Required[str] """The content of the partial.""" diff --git a/src/knock_mapi/types/partial_upsert_response.py b/src/knock_mapi/types/partial_upsert_response.py index 72fa2b2..93ef6fc 100644 --- a/src/knock_mapi/types/partial_upsert_response.py +++ b/src/knock_mapi/types/partial_upsert_response.py @@ -7,5 +7,7 @@ class PartialUpsertResponse(BaseModel): + """Wraps the Partial response under the `partial` key.""" + partial: Partial """A partial is a reusable piece of content that can be used in a template.""" diff --git a/src/knock_mapi/types/partial_validate_params.py b/src/knock_mapi/types/partial_validate_params.py index affc737..c102290 100644 --- a/src/knock_mapi/types/partial_validate_params.py +++ b/src/knock_mapi/types/partial_validate_params.py @@ -23,6 +23,8 @@ class PartialValidateParams(TypedDict, total=False): class Partial(TypedDict, total=False): + """A partial object with attributes to update or create a partial.""" + content: Required[str] """The content of the partial.""" diff --git a/src/knock_mapi/types/partial_validate_response.py b/src/knock_mapi/types/partial_validate_response.py index 11cfea2..a738e33 100644 --- a/src/knock_mapi/types/partial_validate_response.py +++ b/src/knock_mapi/types/partial_validate_response.py @@ -7,5 +7,7 @@ class PartialValidateResponse(BaseModel): + """Wraps the Partial response under the `partial` key.""" + partial: Partial """A partial is a reusable piece of content that can be used in a template.""" diff --git a/src/knock_mapi/types/push_channel_settings.py b/src/knock_mapi/types/push_channel_settings.py index 0da4993..7437aef 100644 --- a/src/knock_mapi/types/push_channel_settings.py +++ b/src/knock_mapi/types/push_channel_settings.py @@ -8,6 +8,11 @@ class PushChannelSettings(BaseModel): + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + token_deregistration: Optional[bool] = None """Whether to deregister a push-token when a push send hard bounces. diff --git a/src/knock_mapi/types/push_channel_settings_param.py b/src/knock_mapi/types/push_channel_settings_param.py index 962713d..7645184 100644 --- a/src/knock_mapi/types/push_channel_settings_param.py +++ b/src/knock_mapi/types/push_channel_settings_param.py @@ -8,6 +8,11 @@ class PushChannelSettingsParam(TypedDict, total=False): + """Push channel settings. + + Only used as configuration as part of a workflow channel step. + """ + token_deregistration: bool """Whether to deregister a push-token when a push send hard bounces. diff --git a/src/knock_mapi/types/push_template.py b/src/knock_mapi/types/push_template.py index bee5c8c..ec7544e 100644 --- a/src/knock_mapi/types/push_template.py +++ b/src/knock_mapi/types/push_template.py @@ -9,6 +9,10 @@ class Settings(BaseModel): + """ + The [settings](https://docs.knock.app/integrations/sms/settings-and-overrides) for the push template. Can be omitted. + """ + delivery_type: Optional[Literal["silent", "content"]] = None """The delivery type of the push notification. @@ -21,6 +25,8 @@ class Settings(BaseModel): class PushTemplate(BaseModel): + """A push notification template.""" + text_body: str """The body of the push notification.""" diff --git a/src/knock_mapi/types/push_template_param.py b/src/knock_mapi/types/push_template_param.py index a1e75da..4571b22 100644 --- a/src/knock_mapi/types/push_template_param.py +++ b/src/knock_mapi/types/push_template_param.py @@ -9,6 +9,10 @@ class Settings(TypedDict, total=False): + """ + The [settings](https://docs.knock.app/integrations/sms/settings-and-overrides) for the push template. Can be omitted. + """ + delivery_type: Literal["silent", "content"] """The delivery type of the push notification. @@ -21,6 +25,8 @@ class Settings(TypedDict, total=False): class PushTemplateParam(TypedDict, total=False): + """A push notification template.""" + text_body: Required[str] """The body of the push notification.""" diff --git a/src/knock_mapi/types/request_template.py b/src/knock_mapi/types/request_template.py index 146ed3e..feeb410 100644 --- a/src/knock_mapi/types/request_template.py +++ b/src/knock_mapi/types/request_template.py @@ -25,6 +25,8 @@ class QueryParamsUnionMember1(BaseModel): class RequestTemplate(BaseModel): + """A request template for a fetch function step.""" + method: Literal["get", "post", "put", "delete", "patch"] """The HTTP method of the request.""" diff --git a/src/knock_mapi/types/request_template_param.py b/src/knock_mapi/types/request_template_param.py index d2f4e8c..7ca91cc 100644 --- a/src/knock_mapi/types/request_template_param.py +++ b/src/knock_mapi/types/request_template_param.py @@ -25,6 +25,8 @@ class QueryParamsUnionMember1(TypedDict, total=False): class RequestTemplateParam(TypedDict, total=False): + """A request template for a fetch function step.""" + method: Required[Literal["get", "post", "put", "delete", "patch"]] """The HTTP method of the request.""" diff --git a/src/knock_mapi/types/send_window.py b/src/knock_mapi/types/send_window.py index 49536d8..c8bfbec 100644 --- a/src/knock_mapi/types/send_window.py +++ b/src/knock_mapi/types/send_window.py @@ -11,6 +11,8 @@ class SendWindow(BaseModel): + """A send window time for a notification. Describes a single day.""" + day: Literal["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] """The day of the week.""" diff --git a/src/knock_mapi/types/send_window_param.py b/src/knock_mapi/types/send_window_param.py index 9e2f881..f2756d3 100644 --- a/src/knock_mapi/types/send_window_param.py +++ b/src/knock_mapi/types/send_window_param.py @@ -17,6 +17,8 @@ class SendWindowParam(_SendWindowParamReservedKeywords, total=False): + """A send window time for a notification. Describes a single day.""" + day: Required[Literal["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]] """The day of the week.""" diff --git a/src/knock_mapi/types/shared/page_info.py b/src/knock_mapi/types/shared/page_info.py index c795ac5..088aead 100644 --- a/src/knock_mapi/types/shared/page_info.py +++ b/src/knock_mapi/types/shared/page_info.py @@ -8,6 +8,8 @@ class PageInfo(BaseModel): + """The information about a paginated result.""" + page_size: int """The number of entries to fetch per-page.""" diff --git a/src/knock_mapi/types/sms_channel_settings.py b/src/knock_mapi/types/sms_channel_settings.py index 3298e19..f5c5657 100644 --- a/src/knock_mapi/types/sms_channel_settings.py +++ b/src/knock_mapi/types/sms_channel_settings.py @@ -8,5 +8,10 @@ class SMSChannelSettings(BaseModel): + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + link_tracking: Optional[bool] = None """Whether to track link clicks on SMS notifications.""" diff --git a/src/knock_mapi/types/sms_channel_settings_param.py b/src/knock_mapi/types/sms_channel_settings_param.py index 489eaa7..2ac1b97 100644 --- a/src/knock_mapi/types/sms_channel_settings_param.py +++ b/src/knock_mapi/types/sms_channel_settings_param.py @@ -8,5 +8,10 @@ class SMSChannelSettingsParam(TypedDict, total=False): + """SMS channel settings. + + Only used as configuration as part of a workflow channel step. + """ + link_tracking: bool """Whether to track link clicks on SMS notifications.""" diff --git a/src/knock_mapi/types/sms_template.py b/src/knock_mapi/types/sms_template.py index 53f9c74..68ca41e 100644 --- a/src/knock_mapi/types/sms_template.py +++ b/src/knock_mapi/types/sms_template.py @@ -8,6 +8,10 @@ class Settings(BaseModel): + """ + The [settings](https://docs.knock.app/integrations/sms/settings-and-overrides) for the SMS template. + """ + payload_overrides: Optional[str] = None """A JSON object that overrides the payload sent to the SMS provider.""" @@ -19,6 +23,8 @@ class Settings(BaseModel): class SMSTemplate(BaseModel): + """An SMS template.""" + text_body: str """The message of the SMS.""" diff --git a/src/knock_mapi/types/sms_template_param.py b/src/knock_mapi/types/sms_template_param.py index f289f3e..f3ef870 100644 --- a/src/knock_mapi/types/sms_template_param.py +++ b/src/knock_mapi/types/sms_template_param.py @@ -9,6 +9,10 @@ class Settings(TypedDict, total=False): + """ + The [settings](https://docs.knock.app/integrations/sms/settings-and-overrides) for the SMS template. + """ + payload_overrides: Optional[str] """A JSON object that overrides the payload sent to the SMS provider.""" @@ -20,6 +24,8 @@ class Settings(TypedDict, total=False): class SMSTemplateParam(TypedDict, total=False): + """An SMS template.""" + text_body: Required[str] """The message of the SMS.""" diff --git a/src/knock_mapi/types/translation.py b/src/knock_mapi/types/translation.py index 5e5e252..310ee78 100644 --- a/src/knock_mapi/types/translation.py +++ b/src/knock_mapi/types/translation.py @@ -9,6 +9,8 @@ class Translation(BaseModel): + """A translation object.""" + content: str """ A JSON encoded string containing the key-value pairs of translation references diff --git a/src/knock_mapi/types/translation_retrieve_response.py b/src/knock_mapi/types/translation_retrieve_response.py index ed47f7c..4e9e5a7 100644 --- a/src/knock_mapi/types/translation_retrieve_response.py +++ b/src/knock_mapi/types/translation_retrieve_response.py @@ -7,5 +7,7 @@ class TranslationRetrieveResponse(BaseModel): + """Wraps the Translation response under the `translation` key.""" + translation: Translation """A translation object.""" diff --git a/src/knock_mapi/types/translation_upsert_params.py b/src/knock_mapi/types/translation_upsert_params.py index fdd5dae..86e96ea 100644 --- a/src/knock_mapi/types/translation_upsert_params.py +++ b/src/knock_mapi/types/translation_upsert_params.py @@ -43,6 +43,10 @@ class TranslationUpsertParams(TypedDict, total=False): class Translation(TypedDict, total=False): + """ + A translation object with a content attribute used to update or create a translation. + """ + content: Required[str] """ A JSON encoded string containing the key-value pairs of translation references diff --git a/src/knock_mapi/types/translation_upsert_response.py b/src/knock_mapi/types/translation_upsert_response.py index bf265b7..533daf7 100644 --- a/src/knock_mapi/types/translation_upsert_response.py +++ b/src/knock_mapi/types/translation_upsert_response.py @@ -7,5 +7,7 @@ class TranslationUpsertResponse(BaseModel): + """Wraps the Translation response under the `translation` key.""" + translation: Translation """A translation object.""" diff --git a/src/knock_mapi/types/translation_validate_params.py b/src/knock_mapi/types/translation_validate_params.py index f17e880..e926ed9 100644 --- a/src/knock_mapi/types/translation_validate_params.py +++ b/src/knock_mapi/types/translation_validate_params.py @@ -25,6 +25,10 @@ class TranslationValidateParams(TypedDict, total=False): class Translation(TypedDict, total=False): + """ + A translation object with a content attribute used to update or create a translation. + """ + content: Required[str] """ A JSON encoded string containing the key-value pairs of translation references diff --git a/src/knock_mapi/types/translation_validate_response.py b/src/knock_mapi/types/translation_validate_response.py index 5bebf08..ac4fcc2 100644 --- a/src/knock_mapi/types/translation_validate_response.py +++ b/src/knock_mapi/types/translation_validate_response.py @@ -7,5 +7,7 @@ class TranslationValidateResponse(BaseModel): + """Wraps the Translation response under the `translation` key.""" + translation: Translation """A translation object.""" diff --git a/src/knock_mapi/types/variable.py b/src/knock_mapi/types/variable.py index 45fdb0b..9f07f37 100644 --- a/src/knock_mapi/types/variable.py +++ b/src/knock_mapi/types/variable.py @@ -10,6 +10,8 @@ class Variable(BaseModel): + """An environment variable object.""" + inserted_at: datetime """The timestamp of when the variable was created.""" diff --git a/src/knock_mapi/types/webhook_template.py b/src/knock_mapi/types/webhook_template.py index d62790e..e9ebbd0 100644 --- a/src/knock_mapi/types/webhook_template.py +++ b/src/knock_mapi/types/webhook_template.py @@ -25,6 +25,11 @@ class QueryParam(BaseModel): class WebhookTemplate(BaseModel): + """A webhook template. + + By default, a webhook step will use the request settings you configured in your webhook channel. You can override this as you see fit on a per-step basis. + """ + method: Literal["get", "post", "put", "delete", "patch"] """The HTTP method of the webhook.""" diff --git a/src/knock_mapi/types/webhook_template_param.py b/src/knock_mapi/types/webhook_template_param.py index 29af1d6..39e6100 100644 --- a/src/knock_mapi/types/webhook_template_param.py +++ b/src/knock_mapi/types/webhook_template_param.py @@ -25,6 +25,11 @@ class QueryParam(TypedDict, total=False): class WebhookTemplateParam(TypedDict, total=False): + """A webhook template. + + By default, a webhook step will use the request settings you configured in your webhook channel. You can override this as you see fit on a per-step basis. + """ + method: Required[Literal["get", "post", "put", "delete", "patch"]] """The HTTP method of the webhook.""" diff --git a/src/knock_mapi/types/workflow.py b/src/knock_mapi/types/workflow.py index 3048969..e6079f3 100644 --- a/src/knock_mapi/types/workflow.py +++ b/src/knock_mapi/types/workflow.py @@ -13,6 +13,8 @@ class Settings(BaseModel): + """A map of workflow settings.""" + is_commercial: Optional[bool] = None """Whether the workflow is commercial. Defaults to false.""" @@ -25,6 +27,8 @@ class Settings(BaseModel): class Workflow(BaseModel): + """A workflow object.""" + active: bool """ Whether the workflow is diff --git a/src/knock_mapi/types/workflow_activate_response.py b/src/knock_mapi/types/workflow_activate_response.py index 77b68da..a63e35d 100644 --- a/src/knock_mapi/types/workflow_activate_response.py +++ b/src/knock_mapi/types/workflow_activate_response.py @@ -8,6 +8,8 @@ class WorkflowActivateResponse(BaseModel): + """Wraps the Workflow response under the `workflow` key.""" + workflow: "Workflow" """A workflow object.""" diff --git a/src/knock_mapi/types/workflow_batch_step.py b/src/knock_mapi/types/workflow_batch_step.py index ee09ea9..68ecbc2 100644 --- a/src/knock_mapi/types/workflow_batch_step.py +++ b/src/knock_mapi/types/workflow_batch_step.py @@ -10,6 +10,8 @@ class Settings(BaseModel): + """The settings for the batch step.""" + batch_execution_mode: Optional[Literal["accumulate", "flush_leading"]] = None """The execution mode of the batch step. @@ -55,6 +57,11 @@ class Settings(BaseModel): class WorkflowBatchStep(BaseModel): + """A batch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/batch-function). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_batch_step_param.py b/src/knock_mapi/types/workflow_batch_step_param.py index bea4c5b..40e4ca8 100644 --- a/src/knock_mapi/types/workflow_batch_step_param.py +++ b/src/knock_mapi/types/workflow_batch_step_param.py @@ -11,6 +11,8 @@ class Settings(TypedDict, total=False): + """The settings for the batch step.""" + batch_execution_mode: Optional[Literal["accumulate", "flush_leading"]] """The execution mode of the batch step. @@ -56,6 +58,11 @@ class Settings(TypedDict, total=False): class WorkflowBatchStepParam(TypedDict, total=False): + """A batch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/batch-function). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_branch_step.py b/src/knock_mapi/types/workflow_branch_step.py index f6f269c..5aa4d25 100644 --- a/src/knock_mapi/types/workflow_branch_step.py +++ b/src/knock_mapi/types/workflow_branch_step.py @@ -12,6 +12,8 @@ class Branch(BaseModel): + """A branch in a branch step.""" + conditions: Optional[ConditionGroup] = None """A group of conditions to be evaluated.""" @@ -26,6 +28,11 @@ class Branch(BaseModel): class WorkflowBranchStep(BaseModel): + """A branch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/branch-function). + """ + branches: List[Branch] """A list of workflow branches to be evaluated.""" diff --git a/src/knock_mapi/types/workflow_branch_step_param.py b/src/knock_mapi/types/workflow_branch_step_param.py index aab34f8..1611fbc 100644 --- a/src/knock_mapi/types/workflow_branch_step_param.py +++ b/src/knock_mapi/types/workflow_branch_step_param.py @@ -11,6 +11,8 @@ class Branch(TypedDict, total=False): + """A branch in a branch step.""" + conditions: Optional[ConditionGroupParam] """A group of conditions to be evaluated.""" @@ -25,6 +27,11 @@ class Branch(TypedDict, total=False): class WorkflowBranchStepParam(TypedDict, total=False): + """A branch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/branch-function). + """ + branches: Required[Iterable[Branch]] """A list of workflow branches to be evaluated.""" diff --git a/src/knock_mapi/types/workflow_chat_step.py b/src/knock_mapi/types/workflow_chat_step.py index 7d79dfd..904e950 100644 --- a/src/knock_mapi/types/workflow_chat_step.py +++ b/src/knock_mapi/types/workflow_chat_step.py @@ -13,6 +13,11 @@ class WorkflowChatStep(BaseModel): + """A chat step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_chat_step_param.py b/src/knock_mapi/types/workflow_chat_step_param.py index 1834ac8..57716e1 100644 --- a/src/knock_mapi/types/workflow_chat_step_param.py +++ b/src/knock_mapi/types/workflow_chat_step_param.py @@ -14,6 +14,11 @@ class WorkflowChatStepParam(TypedDict, total=False): + """A chat step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_delay_step.py b/src/knock_mapi/types/workflow_delay_step.py index e14ac7e..7574113 100644 --- a/src/knock_mapi/types/workflow_delay_step.py +++ b/src/knock_mapi/types/workflow_delay_step.py @@ -11,6 +11,11 @@ class Settings(BaseModel): + """The settings for the delay step. + + Both fields can be set to compute a delay where `delay_for` is an offset from the `delay_until_field_path`. + """ + delay_for: Optional[Duration] = None """A duration of time, represented as a unit and a value.""" @@ -22,6 +27,11 @@ class Settings(BaseModel): class WorkflowDelayStep(BaseModel): + """A delay function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/delay-function). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_delay_step_param.py b/src/knock_mapi/types/workflow_delay_step_param.py index ffe6510..4750f2d 100644 --- a/src/knock_mapi/types/workflow_delay_step_param.py +++ b/src/knock_mapi/types/workflow_delay_step_param.py @@ -12,6 +12,11 @@ class Settings(TypedDict, total=False): + """The settings for the delay step. + + Both fields can be set to compute a delay where `delay_for` is an offset from the `delay_until_field_path`. + """ + delay_for: Optional[DurationParam] """A duration of time, represented as a unit and a value.""" @@ -23,6 +28,11 @@ class Settings(TypedDict, total=False): class WorkflowDelayStepParam(TypedDict, total=False): + """A delay function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/delay-function). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_email_step.py b/src/knock_mapi/types/workflow_email_step.py index f0cb136..c9a2dae 100644 --- a/src/knock_mapi/types/workflow_email_step.py +++ b/src/knock_mapi/types/workflow_email_step.py @@ -13,6 +13,11 @@ class WorkflowEmailStep(BaseModel): + """An email step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_email_step_param.py b/src/knock_mapi/types/workflow_email_step_param.py index 3bd2f31..6b135cc 100644 --- a/src/knock_mapi/types/workflow_email_step_param.py +++ b/src/knock_mapi/types/workflow_email_step_param.py @@ -14,6 +14,11 @@ class WorkflowEmailStepParam(TypedDict, total=False): + """An email step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_fetch_step.py b/src/knock_mapi/types/workflow_fetch_step.py index a7792b3..0f1ef6d 100644 --- a/src/knock_mapi/types/workflow_fetch_step.py +++ b/src/knock_mapi/types/workflow_fetch_step.py @@ -11,6 +11,11 @@ class WorkflowFetchStep(BaseModel): + """A fetch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/fetch-function). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_fetch_step_param.py b/src/knock_mapi/types/workflow_fetch_step_param.py index 8dd73ec..468d52b 100644 --- a/src/knock_mapi/types/workflow_fetch_step_param.py +++ b/src/knock_mapi/types/workflow_fetch_step_param.py @@ -12,6 +12,11 @@ class WorkflowFetchStepParam(TypedDict, total=False): + """A fetch function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/fetch-function). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_in_app_feed_step.py b/src/knock_mapi/types/workflow_in_app_feed_step.py index fef775c..8b2f5bb 100644 --- a/src/knock_mapi/types/workflow_in_app_feed_step.py +++ b/src/knock_mapi/types/workflow_in_app_feed_step.py @@ -13,6 +13,11 @@ class WorkflowInAppFeedStep(BaseModel): + """An in-app feed step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_in_app_feed_step_param.py b/src/knock_mapi/types/workflow_in_app_feed_step_param.py index 7091256..2056690 100644 --- a/src/knock_mapi/types/workflow_in_app_feed_step_param.py +++ b/src/knock_mapi/types/workflow_in_app_feed_step_param.py @@ -14,6 +14,11 @@ class WorkflowInAppFeedStepParam(TypedDict, total=False): + """An in-app feed step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_push_step.py b/src/knock_mapi/types/workflow_push_step.py index 1aa9623..20873ae 100644 --- a/src/knock_mapi/types/workflow_push_step.py +++ b/src/knock_mapi/types/workflow_push_step.py @@ -13,6 +13,11 @@ class WorkflowPushStep(BaseModel): + """A push step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_push_step_param.py b/src/knock_mapi/types/workflow_push_step_param.py index 4e76176..e303484 100644 --- a/src/knock_mapi/types/workflow_push_step_param.py +++ b/src/knock_mapi/types/workflow_push_step_param.py @@ -14,6 +14,11 @@ class WorkflowPushStepParam(TypedDict, total=False): + """A push step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_retrieve_response.py b/src/knock_mapi/types/workflow_retrieve_response.py index 052d85b..701f8b0 100644 --- a/src/knock_mapi/types/workflow_retrieve_response.py +++ b/src/knock_mapi/types/workflow_retrieve_response.py @@ -13,6 +13,8 @@ class CreatedBy(BaseModel): + """User information.""" + id: str """The user's unique identifier.""" @@ -24,6 +26,8 @@ class CreatedBy(BaseModel): class Settings(BaseModel): + """A map of workflow settings.""" + is_commercial: Optional[bool] = None """Whether the workflow is commercial. Defaults to false.""" @@ -36,6 +40,8 @@ class Settings(BaseModel): class UpdatedBy(BaseModel): + """User information.""" + id: str """The user's unique identifier.""" @@ -47,6 +53,8 @@ class UpdatedBy(BaseModel): class WorkflowRetrieveResponse(BaseModel): + """A workflow object.""" + active: bool """ Whether the workflow is diff --git a/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py index 0db1787..e1ebc15 100644 --- a/src/knock_mapi/types/workflow_run_params.py +++ b/src/knock_mapi/types/workflow_run_params.py @@ -46,6 +46,8 @@ class WorkflowRunParams(TypedDict, total=False): class RecipientObjectRecipientReference(TypedDict, total=False): + """An object reference.""" + id: Required[str] """The ID of the object.""" @@ -57,6 +59,8 @@ class RecipientObjectRecipientReference(TypedDict, total=False): class ActorObjectRecipientReference(TypedDict, total=False): + """An object reference.""" + id: Required[str] """The ID of the object.""" diff --git a/src/knock_mapi/types/workflow_run_response.py b/src/knock_mapi/types/workflow_run_response.py index ebbe9e2..351c312 100644 --- a/src/knock_mapi/types/workflow_run_response.py +++ b/src/knock_mapi/types/workflow_run_response.py @@ -6,5 +6,7 @@ class WorkflowRunResponse(BaseModel): + """A response to a run workflow request.""" + workflow_run_id: str """The ID of the workflow run.""" diff --git a/src/knock_mapi/types/workflow_sms_step.py b/src/knock_mapi/types/workflow_sms_step.py index 1996aed..9dd23fc 100644 --- a/src/knock_mapi/types/workflow_sms_step.py +++ b/src/knock_mapi/types/workflow_sms_step.py @@ -13,6 +13,11 @@ class WorkflowSMSStep(BaseModel): + """A SMS step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_sms_step_param.py b/src/knock_mapi/types/workflow_sms_step_param.py index ee945a4..f8fb916 100644 --- a/src/knock_mapi/types/workflow_sms_step_param.py +++ b/src/knock_mapi/types/workflow_sms_step_param.py @@ -14,6 +14,11 @@ class WorkflowSMSStepParam(TypedDict, total=False): + """A SMS step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_throttle_step.py b/src/knock_mapi/types/workflow_throttle_step.py index 6f1d4fc..47d95a0 100644 --- a/src/knock_mapi/types/workflow_throttle_step.py +++ b/src/knock_mapi/types/workflow_throttle_step.py @@ -11,6 +11,8 @@ class Settings(BaseModel): + """The settings for the throttle step.""" + throttle_key: Optional[str] = None """The data property to use to throttle notifications per recipient.""" @@ -32,6 +34,11 @@ class Settings(BaseModel): class WorkflowThrottleStep(BaseModel): + """A throttle function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/throttle-function). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_throttle_step_param.py b/src/knock_mapi/types/workflow_throttle_step_param.py index cb9dac7..4a86fd5 100644 --- a/src/knock_mapi/types/workflow_throttle_step_param.py +++ b/src/knock_mapi/types/workflow_throttle_step_param.py @@ -12,6 +12,8 @@ class Settings(TypedDict, total=False): + """The settings for the throttle step.""" + throttle_key: Optional[str] """The data property to use to throttle notifications per recipient.""" @@ -33,6 +35,11 @@ class Settings(TypedDict, total=False): class WorkflowThrottleStepParam(TypedDict, total=False): + """A throttle function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/throttle-function). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step.py b/src/knock_mapi/types/workflow_trigger_workflow_step.py index f14d346..bc96ca1 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step.py @@ -10,6 +10,8 @@ class Settings(BaseModel): + """The settings for the workflow trigger workflow step.""" + actor: Optional[str] = None """The actor to trigger the workflow with. Supports liquid.""" @@ -30,6 +32,11 @@ class Settings(BaseModel): class WorkflowTriggerWorkflowStep(BaseModel): + """A workflow trigger function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/trigger-workflow-function). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py index 6f78254..cd0a2f3 100644 --- a/src/knock_mapi/types/workflow_trigger_workflow_step_param.py +++ b/src/knock_mapi/types/workflow_trigger_workflow_step_param.py @@ -11,6 +11,8 @@ class Settings(TypedDict, total=False): + """The settings for the workflow trigger workflow step.""" + actor: str """The actor to trigger the workflow with. Supports liquid.""" @@ -31,6 +33,11 @@ class Settings(TypedDict, total=False): class WorkflowTriggerWorkflowStepParam(TypedDict, total=False): + """A workflow trigger function step. + + Read more in the [docs](https://docs.knock.app/designing-workflows/trigger-workflow-function). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_upsert_params.py b/src/knock_mapi/types/workflow_upsert_params.py index 2f1d86d..ee15bff 100644 --- a/src/knock_mapi/types/workflow_upsert_params.py +++ b/src/knock_mapi/types/workflow_upsert_params.py @@ -35,6 +35,8 @@ class WorkflowUpsertParams(TypedDict, total=False): class WorkflowSettings(TypedDict, total=False): + """A map of workflow settings.""" + is_commercial: bool """Whether the workflow is commercial. Defaults to false.""" @@ -47,6 +49,8 @@ class WorkflowSettings(TypedDict, total=False): class Workflow(TypedDict, total=False): + """A workflow request for upserting a workflow.""" + name: Required[str] """A name for the workflow. Must be at maximum 255 characters in length.""" diff --git a/src/knock_mapi/types/workflow_upsert_response.py b/src/knock_mapi/types/workflow_upsert_response.py index ccd4945..a550a4b 100644 --- a/src/knock_mapi/types/workflow_upsert_response.py +++ b/src/knock_mapi/types/workflow_upsert_response.py @@ -8,6 +8,8 @@ class WorkflowUpsertResponse(BaseModel): + """Wraps the Workflow response under the `workflow` key.""" + workflow: "Workflow" """A workflow object.""" diff --git a/src/knock_mapi/types/workflow_validate_params.py b/src/knock_mapi/types/workflow_validate_params.py index 14d0ccc..d4599d9 100644 --- a/src/knock_mapi/types/workflow_validate_params.py +++ b/src/knock_mapi/types/workflow_validate_params.py @@ -26,6 +26,8 @@ class WorkflowValidateParams(TypedDict, total=False): class WorkflowSettings(TypedDict, total=False): + """A map of workflow settings.""" + is_commercial: bool """Whether the workflow is commercial. Defaults to false.""" @@ -38,6 +40,8 @@ class WorkflowSettings(TypedDict, total=False): class Workflow(TypedDict, total=False): + """A workflow request for upserting a workflow.""" + name: Required[str] """A name for the workflow. Must be at maximum 255 characters in length.""" diff --git a/src/knock_mapi/types/workflow_validate_response.py b/src/knock_mapi/types/workflow_validate_response.py index 52c20cb..f99bd30 100644 --- a/src/knock_mapi/types/workflow_validate_response.py +++ b/src/knock_mapi/types/workflow_validate_response.py @@ -8,6 +8,8 @@ class WorkflowValidateResponse(BaseModel): + """Wraps the Workflow response under the `workflow` key.""" + workflow: "Workflow" """A workflow object.""" diff --git a/src/knock_mapi/types/workflow_webhook_step.py b/src/knock_mapi/types/workflow_webhook_step.py index 4c55377..40395fc 100644 --- a/src/knock_mapi/types/workflow_webhook_step.py +++ b/src/knock_mapi/types/workflow_webhook_step.py @@ -12,6 +12,11 @@ class WorkflowWebhookStep(BaseModel): + """A webhook step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: str """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflow_webhook_step_param.py b/src/knock_mapi/types/workflow_webhook_step_param.py index ee61ab7..01b2c89 100644 --- a/src/knock_mapi/types/workflow_webhook_step_param.py +++ b/src/knock_mapi/types/workflow_webhook_step_param.py @@ -13,6 +13,11 @@ class WorkflowWebhookStepParam(TypedDict, total=False): + """A webhook step within a workflow. + + Read more in the [docs](https://docs.knock.app/designing-workflows/channel-step). + """ + ref: Required[str] """The reference key of the workflow step. Must be unique per workflow.""" diff --git a/src/knock_mapi/types/workflows/step_preview_template_params.py b/src/knock_mapi/types/workflows/step_preview_template_params.py index 4f320f4..70e958a 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_params.py +++ b/src/knock_mapi/types/workflows/step_preview_template_params.py @@ -46,6 +46,8 @@ class StepPreviewTemplateParams(TypedDict, total=False): class RecipientObjectRecipientReference(TypedDict, total=False): + """An object reference.""" + id: Required[str] """The ID of the object.""" @@ -57,6 +59,8 @@ class RecipientObjectRecipientReference(TypedDict, total=False): class ActorObjectRecipientReference(TypedDict, total=False): + """An object reference.""" + id: Required[str] """The ID of the object.""" diff --git a/src/knock_mapi/types/workflows/step_preview_template_response.py b/src/knock_mapi/types/workflows/step_preview_template_response.py index 83939bc..c79a426 100644 --- a/src/knock_mapi/types/workflows/step_preview_template_response.py +++ b/src/knock_mapi/types/workflows/step_preview_template_response.py @@ -17,6 +17,8 @@ class StepPreviewTemplateResponse(BaseModel): + """A response to a preview workflow template request.""" + content_type: Literal["email", "in_app_feed", "push", "chat", "sms", "http"] """The content type of the preview.""" From ea01174beaa38a05e72661d451743db515ba8de0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 19:18:58 +0000 Subject: [PATCH 098/101] chore(internal): add missing files argument to base client --- src/knock_mapi/_base_client.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index 3b0b3e4..de12281 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -1247,9 +1247,12 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1767,9 +1770,12 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return await self.request(cast_to, opts) async def put( From 589d59b073e5c0293f8c910875d3c6d68ccd9b54 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:20:02 +0000 Subject: [PATCH 099/101] chore: speedup initial import --- src/knock_mapi/_client.py | 750 ++++++++++++++++++++++++++++++-------- 1 file changed, 602 insertions(+), 148 deletions(-) diff --git a/src/knock_mapi/_client.py b/src/knock_mapi/_client.py index 7d66473..bd2f5f4 100644 --- a/src/knock_mapi/_client.py +++ b/src/knock_mapi/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Mapping +from typing import TYPE_CHECKING, Any, Mapping from typing_extensions import Self, override import httpx @@ -20,23 +20,8 @@ not_given, ) from ._utils import is_given, get_async_library +from ._compat import cached_property from ._version import __version__ -from .resources import ( - auth, - guides, - commits, - api_keys, - branches, - channels, - partials, - variables, - broadcasts, - environments, - translations, - email_layouts, - message_types, - channel_groups, -) from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError, KnockMgmtError from ._base_client import ( @@ -44,7 +29,40 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.workflows import workflows + +if TYPE_CHECKING: + from .resources import ( + auth, + guides, + commits, + api_keys, + branches, + channels, + partials, + variables, + workflows, + broadcasts, + environments, + translations, + email_layouts, + message_types, + channel_groups, + ) + from .resources.auth import AuthResource, AsyncAuthResource + from .resources.guides import GuidesResource, AsyncGuidesResource + from .resources.commits import CommitsResource, AsyncCommitsResource + from .resources.api_keys import APIKeysResource, AsyncAPIKeysResource + from .resources.branches import BranchesResource, AsyncBranchesResource + from .resources.channels import ChannelsResource, AsyncChannelsResource + from .resources.partials import PartialsResource, AsyncPartialsResource + from .resources.variables import VariablesResource, AsyncVariablesResource + from .resources.broadcasts import BroadcastsResource, AsyncBroadcastsResource + from .resources.environments import EnvironmentsResource, AsyncEnvironmentsResource + from .resources.translations import TranslationsResource, AsyncTranslationsResource + from .resources.email_layouts import EmailLayoutsResource, AsyncEmailLayoutsResource + from .resources.message_types import MessageTypesResource, AsyncMessageTypesResource + from .resources.channel_groups import ChannelGroupsResource, AsyncChannelGroupsResource + from .resources.workflows.workflows import WorkflowsResource, AsyncWorkflowsResource __all__ = [ "Timeout", @@ -59,24 +77,6 @@ class KnockMgmt(SyncAPIClient): - email_layouts: email_layouts.EmailLayoutsResource - commits: commits.CommitsResource - partials: partials.PartialsResource - translations: translations.TranslationsResource - workflows: workflows.WorkflowsResource - message_types: message_types.MessageTypesResource - auth: auth.AuthResource - api_keys: api_keys.APIKeysResource - channel_groups: channel_groups.ChannelGroupsResource - channels: channels.ChannelsResource - environments: environments.EnvironmentsResource - variables: variables.VariablesResource - guides: guides.GuidesResource - branches: branches.BranchesResource - broadcasts: broadcasts.BroadcastsResource - with_raw_response: KnockMgmtWithRawResponse - with_streaming_response: KnockMgmtWithStreamedResponse - # client options service_token: str @@ -131,23 +131,103 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.email_layouts = email_layouts.EmailLayoutsResource(self) - self.commits = commits.CommitsResource(self) - self.partials = partials.PartialsResource(self) - self.translations = translations.TranslationsResource(self) - self.workflows = workflows.WorkflowsResource(self) - self.message_types = message_types.MessageTypesResource(self) - self.auth = auth.AuthResource(self) - self.api_keys = api_keys.APIKeysResource(self) - self.channel_groups = channel_groups.ChannelGroupsResource(self) - self.channels = channels.ChannelsResource(self) - self.environments = environments.EnvironmentsResource(self) - self.variables = variables.VariablesResource(self) - self.guides = guides.GuidesResource(self) - self.branches = branches.BranchesResource(self) - self.broadcasts = broadcasts.BroadcastsResource(self) - self.with_raw_response = KnockMgmtWithRawResponse(self) - self.with_streaming_response = KnockMgmtWithStreamedResponse(self) + @cached_property + def email_layouts(self) -> EmailLayoutsResource: + from .resources.email_layouts import EmailLayoutsResource + + return EmailLayoutsResource(self) + + @cached_property + def commits(self) -> CommitsResource: + from .resources.commits import CommitsResource + + return CommitsResource(self) + + @cached_property + def partials(self) -> PartialsResource: + from .resources.partials import PartialsResource + + return PartialsResource(self) + + @cached_property + def translations(self) -> TranslationsResource: + from .resources.translations import TranslationsResource + + return TranslationsResource(self) + + @cached_property + def workflows(self) -> WorkflowsResource: + from .resources.workflows import WorkflowsResource + + return WorkflowsResource(self) + + @cached_property + def message_types(self) -> MessageTypesResource: + from .resources.message_types import MessageTypesResource + + return MessageTypesResource(self) + + @cached_property + def auth(self) -> AuthResource: + from .resources.auth import AuthResource + + return AuthResource(self) + + @cached_property + def api_keys(self) -> APIKeysResource: + from .resources.api_keys import APIKeysResource + + return APIKeysResource(self) + + @cached_property + def channel_groups(self) -> ChannelGroupsResource: + from .resources.channel_groups import ChannelGroupsResource + + return ChannelGroupsResource(self) + + @cached_property + def channels(self) -> ChannelsResource: + from .resources.channels import ChannelsResource + + return ChannelsResource(self) + + @cached_property + def environments(self) -> EnvironmentsResource: + from .resources.environments import EnvironmentsResource + + return EnvironmentsResource(self) + + @cached_property + def variables(self) -> VariablesResource: + from .resources.variables import VariablesResource + + return VariablesResource(self) + + @cached_property + def guides(self) -> GuidesResource: + from .resources.guides import GuidesResource + + return GuidesResource(self) + + @cached_property + def branches(self) -> BranchesResource: + from .resources.branches import BranchesResource + + return BranchesResource(self) + + @cached_property + def broadcasts(self) -> BroadcastsResource: + from .resources.broadcasts import BroadcastsResource + + return BroadcastsResource(self) + + @cached_property + def with_raw_response(self) -> KnockMgmtWithRawResponse: + return KnockMgmtWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> KnockMgmtWithStreamedResponse: + return KnockMgmtWithStreamedResponse(self) @property @override @@ -255,24 +335,6 @@ def _make_status_error( class AsyncKnockMgmt(AsyncAPIClient): - email_layouts: email_layouts.AsyncEmailLayoutsResource - commits: commits.AsyncCommitsResource - partials: partials.AsyncPartialsResource - translations: translations.AsyncTranslationsResource - workflows: workflows.AsyncWorkflowsResource - message_types: message_types.AsyncMessageTypesResource - auth: auth.AsyncAuthResource - api_keys: api_keys.AsyncAPIKeysResource - channel_groups: channel_groups.AsyncChannelGroupsResource - channels: channels.AsyncChannelsResource - environments: environments.AsyncEnvironmentsResource - variables: variables.AsyncVariablesResource - guides: guides.AsyncGuidesResource - branches: branches.AsyncBranchesResource - broadcasts: broadcasts.AsyncBroadcastsResource - with_raw_response: AsyncKnockMgmtWithRawResponse - with_streaming_response: AsyncKnockMgmtWithStreamedResponse - # client options service_token: str @@ -327,23 +389,103 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.email_layouts = email_layouts.AsyncEmailLayoutsResource(self) - self.commits = commits.AsyncCommitsResource(self) - self.partials = partials.AsyncPartialsResource(self) - self.translations = translations.AsyncTranslationsResource(self) - self.workflows = workflows.AsyncWorkflowsResource(self) - self.message_types = message_types.AsyncMessageTypesResource(self) - self.auth = auth.AsyncAuthResource(self) - self.api_keys = api_keys.AsyncAPIKeysResource(self) - self.channel_groups = channel_groups.AsyncChannelGroupsResource(self) - self.channels = channels.AsyncChannelsResource(self) - self.environments = environments.AsyncEnvironmentsResource(self) - self.variables = variables.AsyncVariablesResource(self) - self.guides = guides.AsyncGuidesResource(self) - self.branches = branches.AsyncBranchesResource(self) - self.broadcasts = broadcasts.AsyncBroadcastsResource(self) - self.with_raw_response = AsyncKnockMgmtWithRawResponse(self) - self.with_streaming_response = AsyncKnockMgmtWithStreamedResponse(self) + @cached_property + def email_layouts(self) -> AsyncEmailLayoutsResource: + from .resources.email_layouts import AsyncEmailLayoutsResource + + return AsyncEmailLayoutsResource(self) + + @cached_property + def commits(self) -> AsyncCommitsResource: + from .resources.commits import AsyncCommitsResource + + return AsyncCommitsResource(self) + + @cached_property + def partials(self) -> AsyncPartialsResource: + from .resources.partials import AsyncPartialsResource + + return AsyncPartialsResource(self) + + @cached_property + def translations(self) -> AsyncTranslationsResource: + from .resources.translations import AsyncTranslationsResource + + return AsyncTranslationsResource(self) + + @cached_property + def workflows(self) -> AsyncWorkflowsResource: + from .resources.workflows import AsyncWorkflowsResource + + return AsyncWorkflowsResource(self) + + @cached_property + def message_types(self) -> AsyncMessageTypesResource: + from .resources.message_types import AsyncMessageTypesResource + + return AsyncMessageTypesResource(self) + + @cached_property + def auth(self) -> AsyncAuthResource: + from .resources.auth import AsyncAuthResource + + return AsyncAuthResource(self) + + @cached_property + def api_keys(self) -> AsyncAPIKeysResource: + from .resources.api_keys import AsyncAPIKeysResource + + return AsyncAPIKeysResource(self) + + @cached_property + def channel_groups(self) -> AsyncChannelGroupsResource: + from .resources.channel_groups import AsyncChannelGroupsResource + + return AsyncChannelGroupsResource(self) + + @cached_property + def channels(self) -> AsyncChannelsResource: + from .resources.channels import AsyncChannelsResource + + return AsyncChannelsResource(self) + + @cached_property + def environments(self) -> AsyncEnvironmentsResource: + from .resources.environments import AsyncEnvironmentsResource + + return AsyncEnvironmentsResource(self) + + @cached_property + def variables(self) -> AsyncVariablesResource: + from .resources.variables import AsyncVariablesResource + + return AsyncVariablesResource(self) + + @cached_property + def guides(self) -> AsyncGuidesResource: + from .resources.guides import AsyncGuidesResource + + return AsyncGuidesResource(self) + + @cached_property + def branches(self) -> AsyncBranchesResource: + from .resources.branches import AsyncBranchesResource + + return AsyncBranchesResource(self) + + @cached_property + def broadcasts(self) -> AsyncBroadcastsResource: + from .resources.broadcasts import AsyncBroadcastsResource + + return AsyncBroadcastsResource(self) + + @cached_property + def with_raw_response(self) -> AsyncKnockMgmtWithRawResponse: + return AsyncKnockMgmtWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncKnockMgmtWithStreamedResponse: + return AsyncKnockMgmtWithStreamedResponse(self) @property @override @@ -451,79 +593,391 @@ def _make_status_error( class KnockMgmtWithRawResponse: + _client: KnockMgmt + def __init__(self, client: KnockMgmt) -> None: - self.email_layouts = email_layouts.EmailLayoutsResourceWithRawResponse(client.email_layouts) - self.commits = commits.CommitsResourceWithRawResponse(client.commits) - self.partials = partials.PartialsResourceWithRawResponse(client.partials) - self.translations = translations.TranslationsResourceWithRawResponse(client.translations) - self.workflows = workflows.WorkflowsResourceWithRawResponse(client.workflows) - self.message_types = message_types.MessageTypesResourceWithRawResponse(client.message_types) - self.auth = auth.AuthResourceWithRawResponse(client.auth) - self.api_keys = api_keys.APIKeysResourceWithRawResponse(client.api_keys) - self.channel_groups = channel_groups.ChannelGroupsResourceWithRawResponse(client.channel_groups) - self.channels = channels.ChannelsResourceWithRawResponse(client.channels) - self.environments = environments.EnvironmentsResourceWithRawResponse(client.environments) - self.variables = variables.VariablesResourceWithRawResponse(client.variables) - self.guides = guides.GuidesResourceWithRawResponse(client.guides) - self.branches = branches.BranchesResourceWithRawResponse(client.branches) - self.broadcasts = broadcasts.BroadcastsResourceWithRawResponse(client.broadcasts) + self._client = client + + @cached_property + def email_layouts(self) -> email_layouts.EmailLayoutsResourceWithRawResponse: + from .resources.email_layouts import EmailLayoutsResourceWithRawResponse + + return EmailLayoutsResourceWithRawResponse(self._client.email_layouts) + + @cached_property + def commits(self) -> commits.CommitsResourceWithRawResponse: + from .resources.commits import CommitsResourceWithRawResponse + + return CommitsResourceWithRawResponse(self._client.commits) + + @cached_property + def partials(self) -> partials.PartialsResourceWithRawResponse: + from .resources.partials import PartialsResourceWithRawResponse + + return PartialsResourceWithRawResponse(self._client.partials) + + @cached_property + def translations(self) -> translations.TranslationsResourceWithRawResponse: + from .resources.translations import TranslationsResourceWithRawResponse + + return TranslationsResourceWithRawResponse(self._client.translations) + + @cached_property + def workflows(self) -> workflows.WorkflowsResourceWithRawResponse: + from .resources.workflows import WorkflowsResourceWithRawResponse + + return WorkflowsResourceWithRawResponse(self._client.workflows) + + @cached_property + def message_types(self) -> message_types.MessageTypesResourceWithRawResponse: + from .resources.message_types import MessageTypesResourceWithRawResponse + + return MessageTypesResourceWithRawResponse(self._client.message_types) + + @cached_property + def auth(self) -> auth.AuthResourceWithRawResponse: + from .resources.auth import AuthResourceWithRawResponse + + return AuthResourceWithRawResponse(self._client.auth) + + @cached_property + def api_keys(self) -> api_keys.APIKeysResourceWithRawResponse: + from .resources.api_keys import APIKeysResourceWithRawResponse + + return APIKeysResourceWithRawResponse(self._client.api_keys) + + @cached_property + def channel_groups(self) -> channel_groups.ChannelGroupsResourceWithRawResponse: + from .resources.channel_groups import ChannelGroupsResourceWithRawResponse + + return ChannelGroupsResourceWithRawResponse(self._client.channel_groups) + + @cached_property + def channels(self) -> channels.ChannelsResourceWithRawResponse: + from .resources.channels import ChannelsResourceWithRawResponse + + return ChannelsResourceWithRawResponse(self._client.channels) + + @cached_property + def environments(self) -> environments.EnvironmentsResourceWithRawResponse: + from .resources.environments import EnvironmentsResourceWithRawResponse + + return EnvironmentsResourceWithRawResponse(self._client.environments) + + @cached_property + def variables(self) -> variables.VariablesResourceWithRawResponse: + from .resources.variables import VariablesResourceWithRawResponse + + return VariablesResourceWithRawResponse(self._client.variables) + + @cached_property + def guides(self) -> guides.GuidesResourceWithRawResponse: + from .resources.guides import GuidesResourceWithRawResponse + + return GuidesResourceWithRawResponse(self._client.guides) + + @cached_property + def branches(self) -> branches.BranchesResourceWithRawResponse: + from .resources.branches import BranchesResourceWithRawResponse + + return BranchesResourceWithRawResponse(self._client.branches) + + @cached_property + def broadcasts(self) -> broadcasts.BroadcastsResourceWithRawResponse: + from .resources.broadcasts import BroadcastsResourceWithRawResponse + + return BroadcastsResourceWithRawResponse(self._client.broadcasts) class AsyncKnockMgmtWithRawResponse: + _client: AsyncKnockMgmt + def __init__(self, client: AsyncKnockMgmt) -> None: - self.email_layouts = email_layouts.AsyncEmailLayoutsResourceWithRawResponse(client.email_layouts) - self.commits = commits.AsyncCommitsResourceWithRawResponse(client.commits) - self.partials = partials.AsyncPartialsResourceWithRawResponse(client.partials) - self.translations = translations.AsyncTranslationsResourceWithRawResponse(client.translations) - self.workflows = workflows.AsyncWorkflowsResourceWithRawResponse(client.workflows) - self.message_types = message_types.AsyncMessageTypesResourceWithRawResponse(client.message_types) - self.auth = auth.AsyncAuthResourceWithRawResponse(client.auth) - self.api_keys = api_keys.AsyncAPIKeysResourceWithRawResponse(client.api_keys) - self.channel_groups = channel_groups.AsyncChannelGroupsResourceWithRawResponse(client.channel_groups) - self.channels = channels.AsyncChannelsResourceWithRawResponse(client.channels) - self.environments = environments.AsyncEnvironmentsResourceWithRawResponse(client.environments) - self.variables = variables.AsyncVariablesResourceWithRawResponse(client.variables) - self.guides = guides.AsyncGuidesResourceWithRawResponse(client.guides) - self.branches = branches.AsyncBranchesResourceWithRawResponse(client.branches) - self.broadcasts = broadcasts.AsyncBroadcastsResourceWithRawResponse(client.broadcasts) + self._client = client + + @cached_property + def email_layouts(self) -> email_layouts.AsyncEmailLayoutsResourceWithRawResponse: + from .resources.email_layouts import AsyncEmailLayoutsResourceWithRawResponse + + return AsyncEmailLayoutsResourceWithRawResponse(self._client.email_layouts) + + @cached_property + def commits(self) -> commits.AsyncCommitsResourceWithRawResponse: + from .resources.commits import AsyncCommitsResourceWithRawResponse + + return AsyncCommitsResourceWithRawResponse(self._client.commits) + + @cached_property + def partials(self) -> partials.AsyncPartialsResourceWithRawResponse: + from .resources.partials import AsyncPartialsResourceWithRawResponse + + return AsyncPartialsResourceWithRawResponse(self._client.partials) + + @cached_property + def translations(self) -> translations.AsyncTranslationsResourceWithRawResponse: + from .resources.translations import AsyncTranslationsResourceWithRawResponse + + return AsyncTranslationsResourceWithRawResponse(self._client.translations) + + @cached_property + def workflows(self) -> workflows.AsyncWorkflowsResourceWithRawResponse: + from .resources.workflows import AsyncWorkflowsResourceWithRawResponse + + return AsyncWorkflowsResourceWithRawResponse(self._client.workflows) + + @cached_property + def message_types(self) -> message_types.AsyncMessageTypesResourceWithRawResponse: + from .resources.message_types import AsyncMessageTypesResourceWithRawResponse + + return AsyncMessageTypesResourceWithRawResponse(self._client.message_types) + + @cached_property + def auth(self) -> auth.AsyncAuthResourceWithRawResponse: + from .resources.auth import AsyncAuthResourceWithRawResponse + + return AsyncAuthResourceWithRawResponse(self._client.auth) + + @cached_property + def api_keys(self) -> api_keys.AsyncAPIKeysResourceWithRawResponse: + from .resources.api_keys import AsyncAPIKeysResourceWithRawResponse + + return AsyncAPIKeysResourceWithRawResponse(self._client.api_keys) + + @cached_property + def channel_groups(self) -> channel_groups.AsyncChannelGroupsResourceWithRawResponse: + from .resources.channel_groups import AsyncChannelGroupsResourceWithRawResponse + + return AsyncChannelGroupsResourceWithRawResponse(self._client.channel_groups) + + @cached_property + def channels(self) -> channels.AsyncChannelsResourceWithRawResponse: + from .resources.channels import AsyncChannelsResourceWithRawResponse + + return AsyncChannelsResourceWithRawResponse(self._client.channels) + + @cached_property + def environments(self) -> environments.AsyncEnvironmentsResourceWithRawResponse: + from .resources.environments import AsyncEnvironmentsResourceWithRawResponse + + return AsyncEnvironmentsResourceWithRawResponse(self._client.environments) + + @cached_property + def variables(self) -> variables.AsyncVariablesResourceWithRawResponse: + from .resources.variables import AsyncVariablesResourceWithRawResponse + + return AsyncVariablesResourceWithRawResponse(self._client.variables) + + @cached_property + def guides(self) -> guides.AsyncGuidesResourceWithRawResponse: + from .resources.guides import AsyncGuidesResourceWithRawResponse + + return AsyncGuidesResourceWithRawResponse(self._client.guides) + + @cached_property + def branches(self) -> branches.AsyncBranchesResourceWithRawResponse: + from .resources.branches import AsyncBranchesResourceWithRawResponse + + return AsyncBranchesResourceWithRawResponse(self._client.branches) + + @cached_property + def broadcasts(self) -> broadcasts.AsyncBroadcastsResourceWithRawResponse: + from .resources.broadcasts import AsyncBroadcastsResourceWithRawResponse + + return AsyncBroadcastsResourceWithRawResponse(self._client.broadcasts) class KnockMgmtWithStreamedResponse: + _client: KnockMgmt + def __init__(self, client: KnockMgmt) -> None: - self.email_layouts = email_layouts.EmailLayoutsResourceWithStreamingResponse(client.email_layouts) - self.commits = commits.CommitsResourceWithStreamingResponse(client.commits) - self.partials = partials.PartialsResourceWithStreamingResponse(client.partials) - self.translations = translations.TranslationsResourceWithStreamingResponse(client.translations) - self.workflows = workflows.WorkflowsResourceWithStreamingResponse(client.workflows) - self.message_types = message_types.MessageTypesResourceWithStreamingResponse(client.message_types) - self.auth = auth.AuthResourceWithStreamingResponse(client.auth) - self.api_keys = api_keys.APIKeysResourceWithStreamingResponse(client.api_keys) - self.channel_groups = channel_groups.ChannelGroupsResourceWithStreamingResponse(client.channel_groups) - self.channels = channels.ChannelsResourceWithStreamingResponse(client.channels) - self.environments = environments.EnvironmentsResourceWithStreamingResponse(client.environments) - self.variables = variables.VariablesResourceWithStreamingResponse(client.variables) - self.guides = guides.GuidesResourceWithStreamingResponse(client.guides) - self.branches = branches.BranchesResourceWithStreamingResponse(client.branches) - self.broadcasts = broadcasts.BroadcastsResourceWithStreamingResponse(client.broadcasts) + self._client = client + + @cached_property + def email_layouts(self) -> email_layouts.EmailLayoutsResourceWithStreamingResponse: + from .resources.email_layouts import EmailLayoutsResourceWithStreamingResponse + + return EmailLayoutsResourceWithStreamingResponse(self._client.email_layouts) + + @cached_property + def commits(self) -> commits.CommitsResourceWithStreamingResponse: + from .resources.commits import CommitsResourceWithStreamingResponse + + return CommitsResourceWithStreamingResponse(self._client.commits) + + @cached_property + def partials(self) -> partials.PartialsResourceWithStreamingResponse: + from .resources.partials import PartialsResourceWithStreamingResponse + + return PartialsResourceWithStreamingResponse(self._client.partials) + + @cached_property + def translations(self) -> translations.TranslationsResourceWithStreamingResponse: + from .resources.translations import TranslationsResourceWithStreamingResponse + + return TranslationsResourceWithStreamingResponse(self._client.translations) + + @cached_property + def workflows(self) -> workflows.WorkflowsResourceWithStreamingResponse: + from .resources.workflows import WorkflowsResourceWithStreamingResponse + + return WorkflowsResourceWithStreamingResponse(self._client.workflows) + + @cached_property + def message_types(self) -> message_types.MessageTypesResourceWithStreamingResponse: + from .resources.message_types import MessageTypesResourceWithStreamingResponse + + return MessageTypesResourceWithStreamingResponse(self._client.message_types) + + @cached_property + def auth(self) -> auth.AuthResourceWithStreamingResponse: + from .resources.auth import AuthResourceWithStreamingResponse + + return AuthResourceWithStreamingResponse(self._client.auth) + + @cached_property + def api_keys(self) -> api_keys.APIKeysResourceWithStreamingResponse: + from .resources.api_keys import APIKeysResourceWithStreamingResponse + + return APIKeysResourceWithStreamingResponse(self._client.api_keys) + + @cached_property + def channel_groups(self) -> channel_groups.ChannelGroupsResourceWithStreamingResponse: + from .resources.channel_groups import ChannelGroupsResourceWithStreamingResponse + + return ChannelGroupsResourceWithStreamingResponse(self._client.channel_groups) + + @cached_property + def channels(self) -> channels.ChannelsResourceWithStreamingResponse: + from .resources.channels import ChannelsResourceWithStreamingResponse + + return ChannelsResourceWithStreamingResponse(self._client.channels) + + @cached_property + def environments(self) -> environments.EnvironmentsResourceWithStreamingResponse: + from .resources.environments import EnvironmentsResourceWithStreamingResponse + + return EnvironmentsResourceWithStreamingResponse(self._client.environments) + + @cached_property + def variables(self) -> variables.VariablesResourceWithStreamingResponse: + from .resources.variables import VariablesResourceWithStreamingResponse + + return VariablesResourceWithStreamingResponse(self._client.variables) + + @cached_property + def guides(self) -> guides.GuidesResourceWithStreamingResponse: + from .resources.guides import GuidesResourceWithStreamingResponse + + return GuidesResourceWithStreamingResponse(self._client.guides) + + @cached_property + def branches(self) -> branches.BranchesResourceWithStreamingResponse: + from .resources.branches import BranchesResourceWithStreamingResponse + + return BranchesResourceWithStreamingResponse(self._client.branches) + + @cached_property + def broadcasts(self) -> broadcasts.BroadcastsResourceWithStreamingResponse: + from .resources.broadcasts import BroadcastsResourceWithStreamingResponse + + return BroadcastsResourceWithStreamingResponse(self._client.broadcasts) class AsyncKnockMgmtWithStreamedResponse: + _client: AsyncKnockMgmt + def __init__(self, client: AsyncKnockMgmt) -> None: - self.email_layouts = email_layouts.AsyncEmailLayoutsResourceWithStreamingResponse(client.email_layouts) - self.commits = commits.AsyncCommitsResourceWithStreamingResponse(client.commits) - self.partials = partials.AsyncPartialsResourceWithStreamingResponse(client.partials) - self.translations = translations.AsyncTranslationsResourceWithStreamingResponse(client.translations) - self.workflows = workflows.AsyncWorkflowsResourceWithStreamingResponse(client.workflows) - self.message_types = message_types.AsyncMessageTypesResourceWithStreamingResponse(client.message_types) - self.auth = auth.AsyncAuthResourceWithStreamingResponse(client.auth) - self.api_keys = api_keys.AsyncAPIKeysResourceWithStreamingResponse(client.api_keys) - self.channel_groups = channel_groups.AsyncChannelGroupsResourceWithStreamingResponse(client.channel_groups) - self.channels = channels.AsyncChannelsResourceWithStreamingResponse(client.channels) - self.environments = environments.AsyncEnvironmentsResourceWithStreamingResponse(client.environments) - self.variables = variables.AsyncVariablesResourceWithStreamingResponse(client.variables) - self.guides = guides.AsyncGuidesResourceWithStreamingResponse(client.guides) - self.branches = branches.AsyncBranchesResourceWithStreamingResponse(client.branches) - self.broadcasts = broadcasts.AsyncBroadcastsResourceWithStreamingResponse(client.broadcasts) + self._client = client + + @cached_property + def email_layouts(self) -> email_layouts.AsyncEmailLayoutsResourceWithStreamingResponse: + from .resources.email_layouts import AsyncEmailLayoutsResourceWithStreamingResponse + + return AsyncEmailLayoutsResourceWithStreamingResponse(self._client.email_layouts) + + @cached_property + def commits(self) -> commits.AsyncCommitsResourceWithStreamingResponse: + from .resources.commits import AsyncCommitsResourceWithStreamingResponse + + return AsyncCommitsResourceWithStreamingResponse(self._client.commits) + + @cached_property + def partials(self) -> partials.AsyncPartialsResourceWithStreamingResponse: + from .resources.partials import AsyncPartialsResourceWithStreamingResponse + + return AsyncPartialsResourceWithStreamingResponse(self._client.partials) + + @cached_property + def translations(self) -> translations.AsyncTranslationsResourceWithStreamingResponse: + from .resources.translations import AsyncTranslationsResourceWithStreamingResponse + + return AsyncTranslationsResourceWithStreamingResponse(self._client.translations) + + @cached_property + def workflows(self) -> workflows.AsyncWorkflowsResourceWithStreamingResponse: + from .resources.workflows import AsyncWorkflowsResourceWithStreamingResponse + + return AsyncWorkflowsResourceWithStreamingResponse(self._client.workflows) + + @cached_property + def message_types(self) -> message_types.AsyncMessageTypesResourceWithStreamingResponse: + from .resources.message_types import AsyncMessageTypesResourceWithStreamingResponse + + return AsyncMessageTypesResourceWithStreamingResponse(self._client.message_types) + + @cached_property + def auth(self) -> auth.AsyncAuthResourceWithStreamingResponse: + from .resources.auth import AsyncAuthResourceWithStreamingResponse + + return AsyncAuthResourceWithStreamingResponse(self._client.auth) + + @cached_property + def api_keys(self) -> api_keys.AsyncAPIKeysResourceWithStreamingResponse: + from .resources.api_keys import AsyncAPIKeysResourceWithStreamingResponse + + return AsyncAPIKeysResourceWithStreamingResponse(self._client.api_keys) + + @cached_property + def channel_groups(self) -> channel_groups.AsyncChannelGroupsResourceWithStreamingResponse: + from .resources.channel_groups import AsyncChannelGroupsResourceWithStreamingResponse + + return AsyncChannelGroupsResourceWithStreamingResponse(self._client.channel_groups) + + @cached_property + def channels(self) -> channels.AsyncChannelsResourceWithStreamingResponse: + from .resources.channels import AsyncChannelsResourceWithStreamingResponse + + return AsyncChannelsResourceWithStreamingResponse(self._client.channels) + + @cached_property + def environments(self) -> environments.AsyncEnvironmentsResourceWithStreamingResponse: + from .resources.environments import AsyncEnvironmentsResourceWithStreamingResponse + + return AsyncEnvironmentsResourceWithStreamingResponse(self._client.environments) + + @cached_property + def variables(self) -> variables.AsyncVariablesResourceWithStreamingResponse: + from .resources.variables import AsyncVariablesResourceWithStreamingResponse + + return AsyncVariablesResourceWithStreamingResponse(self._client.variables) + + @cached_property + def guides(self) -> guides.AsyncGuidesResourceWithStreamingResponse: + from .resources.guides import AsyncGuidesResourceWithStreamingResponse + + return AsyncGuidesResourceWithStreamingResponse(self._client.guides) + + @cached_property + def branches(self) -> branches.AsyncBranchesResourceWithStreamingResponse: + from .resources.branches import AsyncBranchesResourceWithStreamingResponse + + return AsyncBranchesResourceWithStreamingResponse(self._client.branches) + + @cached_property + def broadcasts(self) -> broadcasts.AsyncBroadcastsResourceWithStreamingResponse: + from .resources.broadcasts import AsyncBroadcastsResourceWithStreamingResponse + + return AsyncBroadcastsResourceWithStreamingResponse(self._client.broadcasts) Client = KnockMgmt From 2cc7a7f8c482a7cb6f3e567ea0ddc843d38fdcc3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:48:28 +0000 Subject: [PATCH 100/101] fix: use async_to_httpx_files in patch method --- src/knock_mapi/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knock_mapi/_base_client.py b/src/knock_mapi/_base_client.py index de12281..d3e9ae0 100644 --- a/src/knock_mapi/_base_client.py +++ b/src/knock_mapi/_base_client.py @@ -1774,7 +1774,7 @@ async def patch( options: RequestOptions = {}, ) -> ResponseT: opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) From cde77829559c80d56250a449ab1b9cf1f5139e81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:49:30 +0000 Subject: [PATCH 101/101] release: 0.1.0-alpha.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 116 ++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/knock_mapi/_version.py | 2 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c476280..ba6c348 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1-alpha.0" + ".": "0.1.0-alpha.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d339161 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,116 @@ +# Changelog + +## 0.1.0-alpha.1 (2025-12-17) + +Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/knocklabs/knock-mgmt-python/compare/v0.0.1-alpha.0...v0.1.0-alpha.1) + +### Features + +* **api:** add missing in-app feed step ([f2d16ba](https://github.com/knocklabs/knock-mgmt-python/commit/f2d16ba352ccce262afc098c2a9e11107fa6335d)) +* **api:** add new guide methods ([6b9a363](https://github.com/knocklabs/knock-mgmt-python/commit/6b9a3630f2860dd489a73ef9b3a205eeba54038b)) +* **api:** add support for broadcasts ([dfff3b6](https://github.com/knocklabs/knock-mgmt-python/commit/dfff3b6aace731ce3cbb498d84760801806d0b0c)) +* **api:** api update ([0d8db91](https://github.com/knocklabs/knock-mgmt-python/commit/0d8db9179968f0f2852473054d207ca5e8de3652)) +* **api:** api update ([6b36373](https://github.com/knocklabs/knock-mgmt-python/commit/6b36373b2cad5c9cccf12a10f8c257b6e97bceae)) +* **api:** api update ([cdf34d7](https://github.com/knocklabs/knock-mgmt-python/commit/cdf34d7231f4907b906279d4f80b57d695acc3d2)) +* **api:** api update ([4563ca2](https://github.com/knocklabs/knock-mgmt-python/commit/4563ca203fcb58abedf61de44bc07c4721f28c94)) +* **api:** api update ([3b657ad](https://github.com/knocklabs/knock-mgmt-python/commit/3b657ada4768db559b1ee96fc69b1f7f34c736c1)) +* **api:** api update ([1ec851f](https://github.com/knocklabs/knock-mgmt-python/commit/1ec851f416e69862f0eb5e98d3eec7bda2dcb4c5)) +* **api:** api update ([83ec5df](https://github.com/knocklabs/knock-mgmt-python/commit/83ec5df95b6865f85e0d3ff24eb061e567c87727)) +* **api:** api update ([6e33c35](https://github.com/knocklabs/knock-mgmt-python/commit/6e33c35c2b5e0e6cd24295edbde61796e6a2f1a3)) +* **api:** api update ([ab44013](https://github.com/knocklabs/knock-mgmt-python/commit/ab44013d8a3f67eee6f5c15e0d580844c7b0a965)) +* **api:** api update ([72a6e7f](https://github.com/knocklabs/knock-mgmt-python/commit/72a6e7f4c68c3cf1a755f3a6953cb79c3c63ac53)) +* **api:** api update ([4416f12](https://github.com/knocklabs/knock-mgmt-python/commit/4416f123258f4b2ab0bebc6c2f17297b9bb04bcc)) +* **api:** api update ([e44de16](https://github.com/knocklabs/knock-mgmt-python/commit/e44de16209fbd7c8fadcbb6478ef216b887bc8d7)) +* **api:** api update ([2e53b16](https://github.com/knocklabs/knock-mgmt-python/commit/2e53b16a3636da45f5378470b334f25b37e9bf27)) +* **api:** api update ([c08046d](https://github.com/knocklabs/knock-mgmt-python/commit/c08046dd8dca83f69eb0b3c4ab6eef57a88ac963)) +* **api:** api update ([36dcd95](https://github.com/knocklabs/knock-mgmt-python/commit/36dcd956b0f8f4881546271d21bccd8b774863aa)) +* **api:** api update ([7008cf7](https://github.com/knocklabs/knock-mgmt-python/commit/7008cf73bfd891d6f4021077c5d63d00b93e7669)) +* **api:** api update ([7399b9f](https://github.com/knocklabs/knock-mgmt-python/commit/7399b9fc0d9c3c46e903cf1183d120397d2af9d3)) +* **api:** api update ([0c1b410](https://github.com/knocklabs/knock-mgmt-python/commit/0c1b41076bed59f3996d9141afc9e73fca1769b2)) +* **api:** api update ([7575d7b](https://github.com/knocklabs/knock-mgmt-python/commit/7575d7b140452cfd8d5c88a3e5e5d4a28b9b6b9f)) +* **api:** api update ([bc2a719](https://github.com/knocklabs/knock-mgmt-python/commit/bc2a719d1aa7fad4194e872ca1c3240c1c042f3f)) +* **api:** api update ([0cad2fb](https://github.com/knocklabs/knock-mgmt-python/commit/0cad2fb280ed744324ded81614829bc683e68a14)) +* **api:** api update ([3cc26f1](https://github.com/knocklabs/knock-mgmt-python/commit/3cc26f16ba95884a10f9fa8669ca9851d0894847)) +* **api:** api update ([21c2b12](https://github.com/knocklabs/knock-mgmt-python/commit/21c2b12a5d87b3987f8fff6859993f2054c44b3f)) +* **api:** api update ([07b0bf9](https://github.com/knocklabs/knock-mgmt-python/commit/07b0bf9ef7044d022823c67bbee43de5ecde93e8)) +* **api:** api update ([3d7feb9](https://github.com/knocklabs/knock-mgmt-python/commit/3d7feb907fb15da8046849fd2bbfbb4f714ee0a2)) +* **api:** api update ([2377550](https://github.com/knocklabs/knock-mgmt-python/commit/23775502141f16fd94989dd3124107e2db4bf0e9)) +* **api:** api update ([7c582f2](https://github.com/knocklabs/knock-mgmt-python/commit/7c582f2a91271f759be8f01e15d33f0652012ff7)) +* **api:** api update ([a65462c](https://github.com/knocklabs/knock-mgmt-python/commit/a65462cbf700ce4955f56b2e670eaa1f2219d78e)) +* **api:** api update ([0bfd014](https://github.com/knocklabs/knock-mgmt-python/commit/0bfd0143c63ab168dcb28f5b49e251f05cfbc6f3)) +* **api:** api update ([b0cf9fc](https://github.com/knocklabs/knock-mgmt-python/commit/b0cf9fcb27c993980e3da9aa6a886efae70c8c38)) +* **api:** api update ([a2de1b8](https://github.com/knocklabs/knock-mgmt-python/commit/a2de1b8da15d469c9050b7d814dc2276a7dde6cf)) +* **api:** api update ([7af3170](https://github.com/knocklabs/knock-mgmt-python/commit/7af3170696535565aa1d576d1dbc754b0e64ff81)) +* **api:** api update ([11d9193](https://github.com/knocklabs/knock-mgmt-python/commit/11d9193173be598000253571040bd523128ea457)) +* **api:** latest spec and config ([b06ccba](https://github.com/knocklabs/knock-mgmt-python/commit/b06ccba6f9b3791a6cbbbd19ad9b27fbceed0067)) +* **api:** manual updates ([070beab](https://github.com/knocklabs/knock-mgmt-python/commit/070beab81747bc7eac7426c124b29b710cb21b07)) +* **api:** manual updates ([29415bd](https://github.com/knocklabs/knock-mgmt-python/commit/29415bd6f87d68167f11ce4aaa71cff02fa55460)) +* **api:** manual updates ([6deba0f](https://github.com/knocklabs/knock-mgmt-python/commit/6deba0f2e192260d524c7ac454cbcbed8458b745)) +* **client:** add follow_redirects request option ([5079fb9](https://github.com/knocklabs/knock-mgmt-python/commit/5079fb92ff59e10bc72b2af1489724f56fcd3911)) +* **client:** add support for aiohttp ([0a040e2](https://github.com/knocklabs/knock-mgmt-python/commit/0a040e281f0077e1707d4225654510a42a3a2fb0)) +* improve future compat with pydantic v3 ([e278ead](https://github.com/knocklabs/knock-mgmt-python/commit/e278eada17a2cdbcb3115f9574a2863fa7690223)) +* **types:** replace List[str] with SequenceNotStr in params ([b683c79](https://github.com/knocklabs/knock-mgmt-python/commit/b683c790f8eb0a6acd4141e455b04433023d8cec)) + + +### Bug Fixes + +* avoid newer type syntax ([8e12c75](https://github.com/knocklabs/knock-mgmt-python/commit/8e12c750a414ffbb92fac0cb1509de522031a0e0)) +* **ci:** correct conditional ([a96a2bb](https://github.com/knocklabs/knock-mgmt-python/commit/a96a2bbd60bd1b9d6b93dd5f83ba658f4934eeae)) +* **ci:** release-doctor — report correct token name ([7021893](https://github.com/knocklabs/knock-mgmt-python/commit/7021893dab2b10080eb01e6a5e665e421ce30e6f)) +* **client:** close streams without requiring full consumption ([b3228b1](https://github.com/knocklabs/knock-mgmt-python/commit/b3228b101a92a0dbba0f330b7992db943525b37c)) +* **client:** correctly parse binary response | stream ([8d0c46b](https://github.com/knocklabs/knock-mgmt-python/commit/8d0c46bca0475d69f0100ced4db27560b0f18b54)) +* compat with Python 3.14 ([50bf20a](https://github.com/knocklabs/knock-mgmt-python/commit/50bf20a54a3ed5b684f2160016bdc0432c1436a6)) +* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([7d0d80e](https://github.com/knocklabs/knock-mgmt-python/commit/7d0d80e4bfd30d6f569003b346ab60b218f6a9e5)) +* ensure streams are always closed ([ee545af](https://github.com/knocklabs/knock-mgmt-python/commit/ee545af593640a9128ffcc8e14b0793e91ec8a5f)) +* **package:** support direct resource imports ([1cb0a5c](https://github.com/knocklabs/knock-mgmt-python/commit/1cb0a5c285e1965ae02d91c89d1e58b5cf4bf7c9)) +* **types:** allow pyright to infer TypedDict types within SequenceNotStr ([f3148fd](https://github.com/knocklabs/knock-mgmt-python/commit/f3148fd2c048f4572c24e7e970c12c8f8e9be96e)) +* use async_to_httpx_files in patch method ([2cc7a7f](https://github.com/knocklabs/knock-mgmt-python/commit/2cc7a7f8c482a7cb6f3e567ea0ddc843d38fdcc3)) + + +### Chores + +* add missing docstrings ([1d22dd0](https://github.com/knocklabs/knock-mgmt-python/commit/1d22dd0866f56e690df4a5bd3197b1a71f0fd19d)) +* bump `httpx-aiohttp` version to 0.1.9 ([c6c6d98](https://github.com/knocklabs/knock-mgmt-python/commit/c6c6d98ec14a7429e16a41aa361b5ec94cbca623)) +* change publish docs url ([aac5b46](https://github.com/knocklabs/knock-mgmt-python/commit/aac5b4663dfda3909e1133acad7fbbf843cdc726)) +* **ci:** change upload type ([06bf7fe](https://github.com/knocklabs/knock-mgmt-python/commit/06bf7febdcdfec47d98cc82a9419e90c375846eb)) +* **ci:** enable for pull requests ([43b4165](https://github.com/knocklabs/knock-mgmt-python/commit/43b4165055db298bf6625629b1eb38d64ab821ff)) +* **ci:** fix installation instructions ([136b83e](https://github.com/knocklabs/knock-mgmt-python/commit/136b83e5dcad2f71b08f48b536dd0e9f463f5a8e)) +* **ci:** only run for pushes and fork pull requests ([f04705e](https://github.com/knocklabs/knock-mgmt-python/commit/f04705e5d5f746990f96f2f950972a8733ff672d)) +* **ci:** upload sdks to package manager ([526aeec](https://github.com/knocklabs/knock-mgmt-python/commit/526aeecc6c6975207ad58e88eed5adc15c04e27d)) +* configure new SDK language ([acf21f3](https://github.com/knocklabs/knock-mgmt-python/commit/acf21f3de35f214f603433f8defee406c0f9a769)) +* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([828d403](https://github.com/knocklabs/knock-mgmt-python/commit/828d403035cb6fcb789b92069124eba8c79088a6)) +* do not install brew dependencies in ./scripts/bootstrap by default ([47f30ba](https://github.com/knocklabs/knock-mgmt-python/commit/47f30baf8a98c54137ee207d0e91c9dd0e271cc4)) +* **docs:** grammar improvements ([b623da9](https://github.com/knocklabs/knock-mgmt-python/commit/b623da9bf447b1df85c9cc200996aa24685de3de)) +* **docs:** remove reference to rye shell ([2ce93ae](https://github.com/knocklabs/knock-mgmt-python/commit/2ce93ae3634eeaf460ddccd643bc4b20d02f5cdc)) +* **docs:** use environment variables for authentication in code snippets ([36bffb1](https://github.com/knocklabs/knock-mgmt-python/commit/36bffb16af013addda71caa6974d6ccb88c50f70)) +* **internal/tests:** avoid race condition with implicit client cleanup ([e2038a8](https://github.com/knocklabs/knock-mgmt-python/commit/e2038a8ccc329b3661f667d48f9f3b0422dd902a)) +* **internal:** add missing files argument to base client ([ea01174](https://github.com/knocklabs/knock-mgmt-python/commit/ea01174beaa38a05e72661d451743db515ba8de0)) +* **internal:** add Sequence related utils ([5c33cb2](https://github.com/knocklabs/knock-mgmt-python/commit/5c33cb28c71fb192aed4579e1aec0eb7e2e09a71)) +* **internal:** avoid errors for isinstance checks on proxies ([7947d31](https://github.com/knocklabs/knock-mgmt-python/commit/7947d31302f3e0e3d43ba21e84aaf0a06e541f5b)) +* **internal:** change ci workflow machines ([914029b](https://github.com/knocklabs/knock-mgmt-python/commit/914029ba51826437a11129275e5df48d049a4c57)) +* **internal:** codegen related update ([6e2e025](https://github.com/knocklabs/knock-mgmt-python/commit/6e2e025ae38d38d50423ff08c4c0171eac8ba5bb)) +* **internal:** codegen related update ([8ffd5af](https://github.com/knocklabs/knock-mgmt-python/commit/8ffd5af66c23e840f4f7be4892b092c862fad587)) +* **internal:** detect missing future annotations with ruff ([39d08bb](https://github.com/knocklabs/knock-mgmt-python/commit/39d08bb5ee700407596d84b9b73e52b38c5ac76b)) +* **internal:** grammar fix (it's -> its) ([ee64945](https://github.com/knocklabs/knock-mgmt-python/commit/ee64945b8a4aa9fe9a6fc275e9128a9467c691fa)) +* **internal:** improve examples ([0680566](https://github.com/knocklabs/knock-mgmt-python/commit/068056627b37ad3595d1f35949525c17849351fb)) +* **internal:** move mypy configurations to `pyproject.toml` file ([e1c9f43](https://github.com/knocklabs/knock-mgmt-python/commit/e1c9f432350da84660420a1bfc2ac49a813ccd11)) +* **internal:** update conftest.py ([2cbbdbc](https://github.com/knocklabs/knock-mgmt-python/commit/2cbbdbcebfd41c2d85f00a6bf88b5fdf9f710c9d)) +* **internal:** update pydantic dependency ([7defb9e](https://github.com/knocklabs/knock-mgmt-python/commit/7defb9ea2c11bbe100c1427f1f89e50038cbec30)) +* **internal:** update pyright exclude list ([6545a42](https://github.com/knocklabs/knock-mgmt-python/commit/6545a423e252a107e9aab73aee0b8ce3df7e083e)) +* **package:** drop Python 3.8 support ([8e266a2](https://github.com/knocklabs/knock-mgmt-python/commit/8e266a26c0677603f2aa2e98b1bd59b29ccd0b46)) +* **readme:** update badges ([bb17cec](https://github.com/knocklabs/knock-mgmt-python/commit/bb17cec1d07a1b218882dcaff2b8019122efa156)) +* speedup initial import ([589d59b](https://github.com/knocklabs/knock-mgmt-python/commit/589d59b073e5c0293f8c910875d3c6d68ccd9b54)) +* **tests:** add tests for httpx client instantiation & proxies ([69f66be](https://github.com/knocklabs/knock-mgmt-python/commit/69f66beff3e47d5247968cecb2de84a0d7ec658d)) +* **tests:** run tests in parallel ([c4adff6](https://github.com/knocklabs/knock-mgmt-python/commit/c4adff61602002577b5240580dc941028e3eb17f)) +* **tests:** simplify `get_platform` test ([dacad65](https://github.com/knocklabs/knock-mgmt-python/commit/dacad65d1ef5042803226b3f2f584a7ce16aa197)) +* **tests:** skip some failing tests on the latest python versions ([0d15d2b](https://github.com/knocklabs/knock-mgmt-python/commit/0d15d2b669b62c4927bd71c31e92cad6a5be78fd)) +* **types:** change optional parameter type from NotGiven to Omit ([02af8f0](https://github.com/knocklabs/knock-mgmt-python/commit/02af8f0a2b0904f9c1b031a14d0b2424f1c286f9)) +* **types:** rebuild Pydantic models after all types are defined ([17498d4](https://github.com/knocklabs/knock-mgmt-python/commit/17498d45291c5d7518d490947d00ccd1fd4cc055)) +* update github action ([ba727ca](https://github.com/knocklabs/knock-mgmt-python/commit/ba727ca6dd9372015c3924ab11faa3e94214f98d)) +* update lockfile ([b80f066](https://github.com/knocklabs/knock-mgmt-python/commit/b80f066cb4de4d97dc2171086d6b48dec1341029)) +* update SDK settings ([0e4d241](https://github.com/knocklabs/knock-mgmt-python/commit/0e4d24129716e977791255bd26561a97ed3191dc)) + + +### Documentation + +* **client:** fix httpx.Timeout documentation reference ([f85ddbe](https://github.com/knocklabs/knock-mgmt-python/commit/f85ddbee1539127553bd259d61db9a155de2268e)) diff --git a/pyproject.toml b/pyproject.toml index 4107f04..9d6eb6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "knock_mapi" -version = "0.0.1-alpha.0" +version = "0.1.0-alpha.1" description = "The official Python library for the knock mgmt API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/knock_mapi/_version.py b/src/knock_mapi/_version.py index 32c8602..5548612 100644 --- a/src/knock_mapi/_version.py +++ b/src/knock_mapi/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "knock_mapi" -__version__ = "0.0.1-alpha.0" # x-release-please-version +__version__ = "0.1.0-alpha.1" # x-release-please-version