diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index caa50bc..b5a78eb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,12 +7,17 @@ on:
- 'integrated/**'
- 'stl-preview-head/**'
- 'stl-preview-base/**'
+ pull_request:
+ branches-ignore:
+ - 'stl-preview-head/**'
+ - 'stl-preview-base/**'
jobs:
lint:
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
@@ -30,10 +35,51 @@ jobs:
- name: Run lints
run: ./scripts/lint
+ build:
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
+ timeout-minutes: 10
+ name: build
+ permissions:
+ contents: read
+ id-token: write
+ runs-on: ${{ github.repository == 'stainless-sdks/knock-mapi-python' && 'depot-ubuntu-24.04' || '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: Install dependencies
+ run: rye sync --all-features
+
+ - name: Run build
+ 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 }}
+ SHA: ${{ github.sha }}
+ run: ./scripts/utils/upload-artifact.sh
+
test:
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
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/.gitignore b/.gitignore
index 8779740..95ceb18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
.prism.log
-.vscode
_dev
__pycache__
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
new file mode 100644
index 0000000..ba6c348
--- /dev/null
+++ b/.release-please-manifest.json
@@ -0,0 +1,3 @@
+{
+ ".": "0.1.0-alpha.1"
+}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 02525ab..0fe50c7 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
+configured_endpoints: 51
+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/.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",
+}
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/CONTRIBUTING.md b/CONTRIBUTING.md
index dc3ee0f..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
@@ -63,7 +62,7 @@ If you’d like to use the repository from source, you can either install from g
To install via git:
```sh
-$ pip install git+ssh://git@github.com/stainless-sdks/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 +120,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..a679cde 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
# Knock Mgmt Python API library
-[](https://pypi.org/project/knock_mapi/)
+
+[)](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).
@@ -15,12 +16,12 @@ 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]
-> 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
@@ -71,6 +72,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:
@@ -247,7 +284,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
@@ -316,9 +353,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 +461,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
@@ -439,7 +476,7 @@ print(knock_mapi.__version__)
## Requirements
-Python 3.8 or higher.
+Python 3.9 or higher.
## Contributing
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.
---
diff --git a/api.md b/api.md
index 8151c12..7c3547f 100644
--- a/api.md
+++ b/api.md
@@ -104,12 +104,18 @@ from knock_mapi.types import (
Workflow,
WorkflowBatchStep,
WorkflowBranchStep,
- WorkflowChannelStep,
+ WorkflowChatStep,
WorkflowDelayStep,
+ WorkflowEmailStep,
WorkflowFetchStep,
+ WorkflowInAppFeedStep,
+ WorkflowPushStep,
+ WorkflowSMSStep,
WorkflowStep,
WorkflowThrottleStep,
WorkflowTriggerWorkflowStep,
+ WorkflowWebhookStep,
+ WorkflowRetrieveResponse,
WorkflowActivateResponse,
WorkflowRunResponse,
WorkflowUpsertResponse,
@@ -119,7 +125,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
@@ -238,3 +244,67 @@ from knock_mapi.types import Variable
Methods:
- client.variables.list(\*\*params) -> SyncEntriesCursor[Variable]
+
+# Guides
+
+Types:
+
+```python
+from knock_mapi.types import (
+ Guide,
+ GuideActivationURLPattern,
+ GuideStep,
+ GuideActivateResponse,
+ GuideArchiveResponse,
+ 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.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
+
+# 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/bin/check-release-environment b/bin/check-release-environment
new file mode 100644
index 0000000..b845b0f
--- /dev/null
+++ b/bin/check-release-environment
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+errors=()
+
+if [ -z "${PYPI_TOKEN}" ]; then
+ errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.")
+fi
+
+lenErrors=${#errors[@]}
+
+if [[ lenErrors -gt 0 ]]; then
+ echo -e "Found the following errors in the release environment:\n"
+
+ for error in "${errors[@]}"; do
+ echo -e "- $error\n"
+ done
+
+ exit 1
+fi
+
+echo "The environment is ready to push releases!"
diff --git a/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 a3caaee..9d6eb6c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,29 +1,32 @@
[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"
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.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",
"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",
@@ -34,16 +37,18 @@ 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"
+[project.optional-dependencies]
+aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.9"]
[tool.rye]
managed = true
# version pins are in requirements-dev.lock
dev-dependencies = [
"pyright==1.1.399",
- "mypy",
+ "mypy==1.17",
"respx",
"pytest",
"pytest-asyncio",
@@ -53,7 +58,7 @@ 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",
]
[tool.rye.scripts]
@@ -121,11 +126,11 @@ 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"]
-addopts = "--tb=short"
+addopts = "--tb=short -n auto"
xfail_strict = true
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
@@ -138,12 +143,13 @@ 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",
".venv",
".nox",
+ ".git",
]
reportImplicitOverride = true
@@ -152,10 +158,62 @@ 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"
-target-version = "py37"
+target-version = "py38"
[tool.ruff.format]
docstring-code-format = true
@@ -168,6 +226,8 @@ select = [
"B",
# remove unused imports
"F401",
+ # check for missing future annotations
+ "FA102",
# bare except statements
"E722",
# unused arguments
@@ -190,6 +250,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"
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/requirements-dev.lock b/requirements-dev.lock
index 2840953..d83630a 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -10,95 +10,140 @@
# universal: false
-e file:.
-annotated-types==0.6.0
+aiohappyeyeballs==2.6.1
+ # via aiohttp
+aiohttp==3.13.2
+ # via httpx-aiohttp
+ # via knock-mapi
+aiosignal==1.4.0
+ # via aiohttp
+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.4.0
+ # via aiohttp
# via nox
-certifi==2023.7.22
+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
-filelock==3.12.4
+execnet==2.1.2
+ # via pytest-xdist
+filelock==3.19.1
# via virtualenv
-h11==0.14.0
+frozenlist==1.8.0
+ # via aiohttp
+ # via aiosignal
+h11==0.16.0
# via httpcore
-httpcore==1.0.2
+httpcore==1.0.9
# via httpx
httpx==0.28.1
+ # via httpx-aiohttp
# via knock-mapi
# via respx
-idna==3.4
+httpx-aiohttp==0.1.9
+ # via knock-mapi
+humanize==4.13.0
+ # via nox
+idna==3.11
# via anyio
# via httpx
-importlib-metadata==7.0.0
-iniconfig==2.0.0
+ # via yarl
+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
-mypy==1.14.1
-mypy-extensions==1.0.0
+multidict==6.7.0
+ # via aiohttp
+ # via yarl
+mypy==1.17.0
+mypy-extensions==1.1.0
# via mypy
-nest-asyncio==1.6.0
-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
-platformdirs==3.11.0
+pathspec==0.12.1
+ # via mypy
+platformdirs==4.4.0
# via virtualenv
-pluggy==1.5.0
+pluggy==1.6.0
# via pytest
-pydantic==2.10.3
+propcache==0.4.1
+ # via aiohttp
+ # via yarl
+pydantic==2.12.5
# via knock-mapi
-pydantic-core==2.27.1
+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
-pytest-asyncio==0.24.0
-python-dateutil==2.8.2
+ # via pytest-xdist
+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
-virtualenv==20.24.5
+ # via pytest-asyncio
+ # via typing-inspection
+ # via virtualenv
+typing-inspection==0.4.2
+ # via pydantic
+virtualenv==20.35.4
# via nox
-zipp==3.17.0
+yarl==1.22.0
+ # via aiohttp
+zipp==3.23.0
# via importlib-metadata
diff --git a/requirements.lock b/requirements.lock
index 4028537..e3375f3 100644
--- a/requirements.lock
+++ b/requirements.lock
@@ -10,36 +10,67 @@
# universal: false
-e file:.
-annotated-types==0.6.0
+aiohappyeyeballs==2.6.1
+ # via aiohttp
+aiohttp==3.13.2
+ # via httpx-aiohttp
+ # via knock-mapi
+aiosignal==1.4.0
+ # via aiohttp
+annotated-types==0.7.0
# via pydantic
-anyio==4.4.0
+anyio==4.12.0
# via httpx
# via knock-mapi
-certifi==2023.7.22
+async-timeout==5.0.1
+ # via aiohttp
+attrs==25.4.0
+ # via aiohttp
+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
-h11==0.14.0
+frozenlist==1.8.0
+ # via aiohttp
+ # via aiosignal
+h11==0.16.0
# via httpcore
-httpcore==1.0.2
+httpcore==1.0.9
# via httpx
httpx==0.28.1
+ # via httpx-aiohttp
+ # via knock-mapi
+httpx-aiohttp==0.1.9
# via knock-mapi
-idna==3.4
+idna==3.11
# via anyio
# via httpx
-pydantic==2.10.3
+ # via yarl
+multidict==6.7.0
+ # via aiohttp
+ # via yarl
+propcache==0.4.1
+ # via aiohttp
+ # via yarl
+pydantic==2.12.5
# via knock-mapi
-pydantic-core==2.27.1
+pydantic-core==2.41.5
# via pydantic
-sniffio==1.3.0
- # via anyio
+sniffio==1.3.1
# via knock-mapi
-typing-extensions==4.12.2
+typing-extensions==4.15.0
+ # via aiosignal
# via anyio
+ # via exceptiongroup
# via knock-mapi
+ # via multidict
# via pydantic
# via pydantic-core
+ # via typing-inspection
+typing-inspection==0.4.2
+ # via pydantic
+yarl==1.22.0
+ # via aiohttp
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
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/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh
new file mode 100755
index 0000000..22e9829
--- /dev/null
+++ b/scripts/utils/upload-artifact.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -exuo pipefail
+
+FILENAME=$(basename dist/*.whl)
+
+RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \
+ -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=$(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 'https://pkg.stainless.com/s/knock-mapi-python/$SHA/$FILENAME'\033[0m"
+else
+ echo -e "\033[31mFailed to upload artifact.\033[0m"
+ exit 1
+fi
diff --git a/src/knock_mapi/__init__.py b/src/knock_mapi/__init__.py
index ea3e26c..e41a2d2 100644
--- a/src/knock_mapi/__init__.py
+++ b/src/knock_mapi/__init__.py
@@ -1,7 +1,9 @@
# 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 ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given
from ._utils import file_from_path
from ._client import (
Client,
@@ -34,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__ = [
@@ -46,7 +48,9 @@
"ProxiesTypes",
"NotGiven",
"NOT_GIVEN",
+ "not_given",
"Omit",
+ "omit",
"KnockMgmtError",
"APIError",
"APIStatusError",
@@ -76,8 +80,12 @@
"DEFAULT_CONNECTION_LIMITS",
"DefaultHttpxClient",
"DefaultAsyncHttpxClient",
+ "DefaultAioHttpClient",
]
+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/_base_client.py b/src/knock_mapi/_base_client.py
index 426b03d..d3e9ae0 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,9 +56,10 @@
RequestOptions,
HttpxRequestFiles,
ModelBuilderProtocol,
+ not_given,
)
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,
@@ -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
@@ -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
@@ -529,6 +529,18 @@ 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:
+ 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)
+ kwargs.pop("data", None)
+
# TODO: report this error to httpx
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
headers=headers,
@@ -540,8 +552,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,
)
@@ -585,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)
@@ -815,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,
@@ -960,6 +970,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
@@ -1068,7 +1081,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}")
@@ -1227,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(
@@ -1279,6 +1302,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
@@ -1287,8 +1328,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):
@@ -1314,7 +1359,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,
@@ -1460,6 +1505,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
@@ -1568,7 +1616,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}")
@@ -1715,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=await async_to_httpx_files(files), **options
+ )
return await self.request(cast_to, opts)
async def put(
@@ -1766,8 +1824,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 fb65def..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, Union, Mapping
+from typing import TYPE_CHECKING, Any, Mapping
from typing_extensions import Self, override
import httpx
@@ -11,29 +11,17 @@
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 ._compat import cached_property
from ._version import __version__
-from .resources import (
- auth,
- commits,
- api_keys,
- channels,
- partials,
- variables,
- 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 (
@@ -41,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",
@@ -56,21 +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
- with_raw_response: KnockMgmtWithRawResponse
- with_streaming_response: KnockMgmtWithStreamedResponse
-
# client options
service_token: str
@@ -79,7 +85,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,
@@ -125,20 +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.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
@@ -165,9 +254,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,
@@ -246,21 +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
- with_raw_response: AsyncKnockMgmtWithRawResponse
- with_streaming_response: AsyncKnockMgmtWithStreamedResponse
-
# client options
service_token: str
@@ -269,7 +343,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,
@@ -315,20 +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.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
@@ -355,9 +512,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,
@@ -436,67 +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._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._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._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._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
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/_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()
diff --git a/src/knock_mapi/_models.py b/src/knock_mapi/_models.py
index 798956f..ca9500b 100644
--- a/src/knock_mapi/_models.py
+++ b/src/knock_mapi/_models.py
@@ -2,9 +2,11 @@
import os
import inspect
-from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, cast
+import weakref
+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,
@@ -49,7 +51,7 @@
strip_annotated_type,
)
from ._compat import (
- PYDANTIC_V2,
+ PYDANTIC_V1,
ConfigDict,
GenericModel as BaseGenericModel,
get_args,
@@ -80,11 +82,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
@@ -94,6 +92,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,
@@ -207,28 +209,32 @@ 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:
- if PYDANTIC_V2:
- _extra[key] = value
- else:
+ parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value
+
+ if PYDANTIC_V1:
_fields_set.add(key)
- fields_values[key] = value
+ 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
@@ -238,7 +244,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
@@ -251,13 +257,15 @@ def model_dump(
mode: Literal["json", "python"] | str = "python",
include: IncEx | None = None,
exclude: IncEx | None = None,
- by_alias: bool = False,
+ 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,
) -> dict[str, Any]:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump
@@ -266,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.
@@ -290,31 +306,38 @@ 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")
+ 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,
- 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,
)
- 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(
self,
*,
indent: int | None = None,
+ ensure_ascii: bool = False,
include: IncEx | None = None,
exclude: IncEx | None = None,
- by_alias: bool = False,
+ 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:
"""Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json
@@ -343,11 +366,17 @@ 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")
+ 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,
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,
@@ -358,15 +387,32 @@ 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}")
- return construct_type(value=value, type_=type_)
+ return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None))
+
+
+def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None:
+ if PYDANTIC_V1:
+ # 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:
@@ -420,7 +466,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 +484,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 and len(metadata) > 0:
+ meta: tuple[Any, ...] = tuple(metadata)
+ elif is_annotated_type(type_):
+ meta = get_args(type_)[1:]
type_ = extract_type_arg(type_, 0)
else:
meta = tuple()
@@ -543,6 +591,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.
@@ -585,8 +636,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
@@ -604,30 +656,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
@@ -639,7 +691,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
@@ -690,7 +742,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))
@@ -737,6 +789,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
idempotency_key: str
json_data: Body
extra_json: AnyMapping
+ follow_redirects: bool
@final
@@ -750,18 +803,19 @@ 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.
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):
@@ -794,9 +848,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/_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/_streaming.py b/src/knock_mapi/_streaming.py
index 43b7d54..ab4cacb 100644
--- a/src/knock_mapi/_streaming.py
+++ b/src/knock_mapi/_streaming.py
@@ -54,12 +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)
-
- # Ensure the entire stream is consumed
- for _sse in iterator:
- ...
+ 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
@@ -118,12 +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)
-
- # Ensure the entire stream is consumed
- async for _sse in iterator:
- ...
+ 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
diff --git a/src/knock_mapi/_types.py b/src/knock_mapi/_types.py
index d27367c..5d8ccc3 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
@@ -100,23 +111,27 @@ class RequestOptions(TypedDict, total=False):
params: Query
extra_json: AnyMapping
idempotency_key: str
+ follow_redirects: bool
# 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
```
"""
@@ -128,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
@@ -144,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})
```
"""
@@ -153,6 +169,9 @@ def __bool__(self) -> Literal[False]:
return False
+omit = Omit()
+
+
@runtime_checkable
class ModelBuilderProtocol(Protocol):
@classmethod
@@ -215,3 +234,28 @@ 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
+ #
+ # 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: ...
+ @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 __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..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,12 +30,20 @@
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,
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,
@@ -55,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/_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/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__()
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:
diff --git a/src/knock_mapi/_utils/_transform.py b/src/knock_mapi/_utils/_transform.py
index b0cc20a..5207549 100644
--- a/src/knock_mapi/_utils/_transform.py
+++ b/src/knock_mapi/_utils/_transform.py
@@ -16,18 +16,20 @@
lru_cache,
is_mapping,
is_iterable,
+ 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,
extract_type_arg,
is_iterable_type,
is_required_type,
+ is_sequence_type,
is_annotated_type,
strip_annotated_type,
)
-from .._compat import get_origin, model_dump, is_typeddict
_T = TypeVar("_T")
@@ -167,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
@@ -184,6 +188,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.
@@ -262,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
@@ -329,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
@@ -346,6 +354,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.
@@ -424,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/_typing.py b/src/knock_mapi/_utils/_typing.py
index 1bac954..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:
@@ -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/src/knock_mapi/_utils/_utils.py b/src/knock_mapi/_utils/_utils.py
index ea3cf3f..eec7f4a 100644
--- a/src/knock_mapi/_utils/_utils.py
+++ b/src/knock_mapi/_utils/_utils.py
@@ -21,8 +21,7 @@
import sniffio
-from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike
-from .._compat import parse_date as parse_date, parse_datetime as parse_datetime
+from .._types import Omit, NotGiven, FileTypes, HeadersLike
_T = TypeVar("_T")
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
@@ -64,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 []
@@ -127,14 +126,14 @@ 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.
# 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
diff --git a/src/knock_mapi/_version.py b/src/knock_mapi/_version.py
index a7e5bf1..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"
+__version__ = "0.1.0-alpha.1" # x-release-please-version
diff --git a/src/knock_mapi/resources/__init__.py b/src/knock_mapi/resources/__init__.py
index 921529c..dbc0be6 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,
@@ -24,6 +32,14 @@
APIKeysResourceWithStreamingResponse,
AsyncAPIKeysResourceWithStreamingResponse,
)
+from .branches import (
+ BranchesResource,
+ AsyncBranchesResource,
+ BranchesResourceWithRawResponse,
+ AsyncBranchesResourceWithRawResponse,
+ BranchesResourceWithStreamingResponse,
+ AsyncBranchesResourceWithStreamingResponse,
+)
from .channels import (
ChannelsResource,
AsyncChannelsResource,
@@ -56,6 +72,14 @@
WorkflowsResourceWithStreamingResponse,
AsyncWorkflowsResourceWithStreamingResponse,
)
+from .broadcasts import (
+ BroadcastsResource,
+ AsyncBroadcastsResource,
+ BroadcastsResourceWithRawResponse,
+ AsyncBroadcastsResourceWithRawResponse,
+ BroadcastsResourceWithStreamingResponse,
+ AsyncBroadcastsResourceWithStreamingResponse,
+)
from .environments import (
EnvironmentsResource,
AsyncEnvironmentsResource,
@@ -170,4 +194,22 @@
"AsyncVariablesResourceWithRawResponse",
"VariablesResourceWithStreamingResponse",
"AsyncVariablesResourceWithStreamingResponse",
+ "GuidesResource",
+ "AsyncGuidesResource",
+ "GuidesResourceWithRawResponse",
+ "AsyncGuidesResourceWithRawResponse",
+ "GuidesResourceWithStreamingResponse",
+ "AsyncGuidesResourceWithStreamingResponse",
+ "BranchesResource",
+ "AsyncBranchesResource",
+ "BranchesResourceWithRawResponse",
+ "AsyncBranchesResourceWithRawResponse",
+ "BranchesResourceWithStreamingResponse",
+ "AsyncBranchesResourceWithStreamingResponse",
+ "BroadcastsResource",
+ "AsyncBroadcastsResource",
+ "BroadcastsResourceWithRawResponse",
+ "AsyncBroadcastsResourceWithRawResponse",
+ "BroadcastsResourceWithStreamingResponse",
+ "AsyncBroadcastsResourceWithStreamingResponse",
]
diff --git a/src/knock_mapi/resources/api_keys.py b/src/knock_mapi/resources/api_keys.py
index 7dd93b1..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
@@ -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)
@@ -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
@@ -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)
@@ -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 83e278c..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 (
@@ -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)
@@ -47,9 +47,13 @@ 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 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(
@@ -66,7 +70,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 +79,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)
@@ -87,9 +91,13 @@ 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 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/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/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/resources/channel_groups.py b/src/knock_mapi/resources/channel_groups.py
index 74c3b7c..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
@@ -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,22 +38,22 @@ 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)
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.
@@ -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,22 +112,22 @@ 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)
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 170f1ca..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
@@ -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,22 +38,23 @@ 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)
def list(
self,
*,
- 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.
@@ -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,
@@ -103,7 +107,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,22 +116,23 @@ 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)
def list(
self,
*,
- 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.
@@ -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/resources/commits.py b/src/knock_mapi/resources/commits.py
index 4e02cac..ffbfad4 100644
--- a/src/knock_mapi/resources/commits.py
+++ b/src/knock_mapi/resources/commits.py
@@ -2,10 +2,13 @@
from __future__ import annotations
+from typing import List, Union
+from typing_extensions import Literal
+
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
@@ -32,7 +35,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 +44,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)
@@ -54,7 +57,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.
@@ -82,16 +85,23 @@ 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,
+ 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,
+ 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,
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.
@@ -105,11 +115,22 @@ 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
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(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
@@ -131,8 +152,11 @@ def list(
"environment": environment,
"after": after,
"before": before,
+ "branch": branch,
"limit": limit,
"promoted": promoted,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
},
commit_list_params.CommitListParams,
),
@@ -144,13 +168,20 @@ def commit_all(
self,
*,
environment: str,
- commit_message: str | NotGiven = NOT_GIVEN,
+ branch: str | Omit = omit,
+ 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,
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.
@@ -158,8 +189,17 @@ 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
+ 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
@@ -178,7 +218,10 @@ def commit_all(
query=maybe_transform(
{
"environment": environment,
+ "branch": branch,
"commit_message": commit_message,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
},
commit_commit_all_params.CommitCommitAllParams,
),
@@ -190,12 +233,19 @@ 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"],
+ 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,
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
@@ -209,7 +259,16 @@ 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.
+
+ 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
@@ -227,7 +286,13 @@ 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,
+ "branch": branch,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ },
+ commit_promote_all_params.CommitPromoteAllParams,
),
),
cast_to=CommitPromoteAllResponse,
@@ -242,7 +307,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.
@@ -274,7 +339,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 +348,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)
@@ -296,7 +361,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.
@@ -324,16 +389,23 @@ 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,
+ 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,
+ 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,
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.
@@ -347,11 +419,22 @@ 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
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(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
@@ -373,8 +456,11 @@ def list(
"environment": environment,
"after": after,
"before": before,
+ "branch": branch,
"limit": limit,
"promoted": promoted,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
},
commit_list_params.CommitListParams,
),
@@ -386,13 +472,20 @@ async def commit_all(
self,
*,
environment: str,
- commit_message: str | NotGiven = NOT_GIVEN,
+ branch: str | Omit = omit,
+ 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,
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.
@@ -400,8 +493,17 @@ 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
+ 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
@@ -420,7 +522,10 @@ 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,
},
commit_commit_all_params.CommitCommitAllParams,
),
@@ -432,12 +537,19 @@ 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"],
+ 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,
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
@@ -451,7 +563,16 @@ 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.
+
+ 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
@@ -469,7 +590,13 @@ 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,
+ "branch": branch,
+ "resource_id": resource_id,
+ "resource_type": resource_type,
+ },
+ commit_promote_all_params.CommitPromoteAllParams,
),
),
cast_to=CommitPromoteAllResponse,
@@ -484,7 +611,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 213de0f..ffa300d 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
@@ -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)
@@ -54,14 +54,15 @@ def retrieve(
email_layout_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> EmailLayout:
"""
Retrieve an email layout by its key, in a given environment.
@@ -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,
@@ -107,17 +112,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncEntriesCursor[EmailLayout]:
"""
Returns a paginated list of email layouts available in a given environment.
@@ -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,
},
@@ -173,15 +183,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +251,13 @@ 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,
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.
@@ -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,
@@ -288,7 +311,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 +320,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)
@@ -306,14 +329,15 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> EmailLayout:
"""
Retrieve an email layout by its key, in a given environment.
@@ -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,
@@ -359,17 +387,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[EmailLayout, AsyncEntriesCursor[EmailLayout]]:
"""
Returns a paginated list of email layouts available in a given environment.
@@ -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,
},
@@ -425,15 +458,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +528,13 @@ 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,
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.
@@ -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/environments.py b/src/knock_mapi/resources/environments.py
index a43c907..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
@@ -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)
@@ -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.
@@ -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)
@@ -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
new file mode 100644
index 0000000..7cc4044
--- /dev/null
+++ b/src/knock_mapi/resources/guides.py
@@ -0,0 +1,1008 @@
+# 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 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
+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_archive_response import GuideArchiveResponse
+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 | 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,
+ ) -> Guide:
+ """
+ Get a guide by its key.
+
+ 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 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,
+ "branch": branch,
+ "hide_uncommitted_changes": hide_uncommitted_changes,
+ },
+ guide_retrieve_params.GuideRetrieveParams,
+ ),
+ ),
+ cast_to=Guide,
+ )
+
+ 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[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.
+
+ 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/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,
+ "branch": branch,
+ "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,
+ 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,
+ ) -> 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.
+
+ 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
+ """
+ ...
+
+ @overload
+ def activate(
+ self,
+ 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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.
+
+ 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.
+
+ 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 | 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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,
+ "branch": branch,
+ },
+ guide_activate_params.GuideActivateParams,
+ ),
+ ),
+ 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,
+ *,
+ 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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.
+
+ 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`.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters 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,
+ "branch": branch,
+ "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,
+ 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,
+ ) -> 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.
+
+ 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 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,
+ "branch": branch,
+ },
+ 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 | 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,
+ ) -> Guide:
+ """
+ Get a guide by its key.
+
+ 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 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,
+ "branch": branch,
+ "hide_uncommitted_changes": hide_uncommitted_changes,
+ },
+ guide_retrieve_params.GuideRetrieveParams,
+ ),
+ ),
+ cast_to=Guide,
+ )
+
+ 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[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.
+
+ 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/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,
+ "branch": branch,
+ "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,
+ 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,
+ ) -> 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.
+
+ 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
+ """
+ ...
+
+ @overload
+ async def activate(
+ self,
+ 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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.
+
+ 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.
+
+ 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 | 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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,
+ "branch": branch,
+ },
+ guide_activate_params.GuideActivateParams,
+ ),
+ ),
+ 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,
+ *,
+ 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.
+ # The extra values given here take precedence over values defined on the client or passed to this 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.
+
+ 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`.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters 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,
+ "branch": branch,
+ "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,
+ 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,
+ ) -> 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.
+
+ 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 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,
+ "branch": branch,
+ },
+ 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.archive = to_raw_response_wrapper(
+ guides.archive,
+ )
+ 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.archive = async_to_raw_response_wrapper(
+ guides.archive,
+ )
+ 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.archive = to_streamed_response_wrapper(
+ guides.archive,
+ )
+ 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.archive = async_to_streamed_response_wrapper(
+ guides.archive,
+ )
+ self.upsert = async_to_streamed_response_wrapper(
+ guides.upsert,
+ )
+ self.validate = async_to_streamed_response_wrapper(
+ guides.validate,
+ )
diff --git a/src/knock_mapi/resources/message_types.py b/src/knock_mapi/resources/message_types.py
index 375f974..dec0f2e 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
@@ -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)
@@ -54,14 +54,15 @@ def retrieve(
message_type_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageType:
"""
Retrieve a message type by its key, in a given environment.
@@ -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,
@@ -107,17 +112,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncEntriesCursor[MessageType]:
"""
Returns a paginated list of message types available in a given environment.
@@ -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,
},
@@ -173,15 +183,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +251,13 @@ 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,
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.
@@ -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,
@@ -289,7 +312,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 +321,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)
@@ -307,14 +330,15 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> MessageType:
"""
Retrieve a message type by its key, in a given environment.
@@ -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,
@@ -360,17 +388,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[MessageType, AsyncEntriesCursor[MessageType]]:
"""
Returns a paginated list of message types available in a given environment.
@@ -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,
},
@@ -426,15 +459,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +529,13 @@ 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,
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.
@@ -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 ee61bf3..90eed9b 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
@@ -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)
@@ -49,14 +49,15 @@ def retrieve(
partial_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Partial:
"""
Get a partial by its key.
@@ -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,
@@ -102,17 +107,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncEntriesCursor[Partial]:
"""
List all partials for a given environment.
@@ -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,
},
@@ -168,15 +178,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +246,13 @@ 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,
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.
@@ -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,
)
@@ -279,7 +304,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 +313,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)
@@ -297,14 +322,15 @@ async def retrieve(
partial_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Partial:
"""
Get a partial by its key.
@@ -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,
@@ -350,17 +380,18 @@ 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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Partial, AsyncEntriesCursor[Partial]]:
"""
List all partials for a given environment.
@@ -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,
},
@@ -416,15 +451,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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.
@@ -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,12 +519,13 @@ 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,
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.
@@ -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 678a0ee..46a9dd5 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
@@ -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)
@@ -57,16 +57,17 @@ 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,
+ branch: str | 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.
@@ -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,
@@ -119,20 +124,21 @@ 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,
+ branch: 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.
@@ -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,
@@ -201,16 +211,17 @@ 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,
+ branch: str | 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
@@ -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,12 +290,13 @@ 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,
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.
@@ -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,
@@ -327,7 +350,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 +359,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)
@@ -345,16 +368,17 @@ 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,
+ branch: str | 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.
@@ -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,
@@ -407,20 +435,21 @@ 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,
+ branch: 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.
@@ -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,
@@ -489,16 +522,17 @@ 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,
+ branch: str | 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
@@ -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,12 +603,13 @@ 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,
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.
@@ -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 95cf469..72d2854 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
@@ -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)
@@ -46,15 +46,16 @@ 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,
+ 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.
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.
@@ -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,
@@ -105,7 +110,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 +119,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)
@@ -122,15 +127,16 @@ 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,
+ 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.
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.
@@ -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 cebf1cf..cdb25ed 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
@@ -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)
@@ -50,15 +50,16 @@ 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,
+ branch: str | Omit = omit,
+ 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.
@@ -69,12 +70,15 @@ 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.
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
@@ -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,
@@ -119,7 +127,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 +136,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)
@@ -139,15 +147,16 @@ 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,
+ branch: str | Omit = omit,
+ 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.
@@ -158,12 +167,15 @@ 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.
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
@@ -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 ab9d85d..c42d4b5 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 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
@@ -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"]
@@ -54,7 +55,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 +64,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)
@@ -72,15 +73,16 @@ def retrieve(
workflow_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
- ) -> Workflow:
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> WorkflowRetrieveResponse:
"""
Retrieve a workflow by its key in a given environment.
@@ -89,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.
@@ -113,29 +118,31 @@ def retrieve(
{
"environment": environment,
"annotate": annotate,
+ "branch": branch,
"hide_uncommitted_changes": hide_uncommitted_changes,
},
workflow_retrieve_params.WorkflowRetrieveParams,
),
),
- cast_to=Workflow,
+ cast_to=WorkflowRetrieveResponse,
)
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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncEntriesCursor[Workflow]:
"""Returns a paginated list of workflows available in a given environment.
@@ -151,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.
@@ -178,6 +188,7 @@ def list(
"after": after,
"annotate": annotate,
"before": before,
+ "branch": branch,
"hide_uncommitted_changes": hide_uncommitted_changes,
"limit": limit,
},
@@ -193,12 +204,13 @@ 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,
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.
@@ -214,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
@@ -232,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,
)
@@ -242,17 +263,18 @@ def run(
workflow_key: str,
*,
environment: str,
- recipients: List[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,
+ 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,
+ 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
@@ -263,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.
@@ -270,7 +295,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
@@ -299,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,
)
@@ -310,15 +341,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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
@@ -333,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`.
@@ -359,6 +394,7 @@ def upsert(
{
"environment": environment,
"annotate": annotate,
+ "branch": branch,
"commit": commit,
"commit_message": commit_message,
},
@@ -374,12 +410,13 @@ 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,
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.
@@ -393,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
@@ -411,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,
)
@@ -428,7 +474,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 +483,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)
@@ -446,15 +492,16 @@ async def retrieve(
workflow_key: str,
*,
environment: str,
- annotate: bool | NotGiven = NOT_GIVEN,
- hide_uncommitted_changes: bool | NotGiven = NOT_GIVEN,
+ 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,
- ) -> Workflow:
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> WorkflowRetrieveResponse:
"""
Retrieve a workflow by its key in a given environment.
@@ -463,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.
@@ -487,29 +537,31 @@ async def retrieve(
{
"environment": environment,
"annotate": annotate,
+ "branch": branch,
"hide_uncommitted_changes": hide_uncommitted_changes,
},
workflow_retrieve_params.WorkflowRetrieveParams,
),
),
- cast_to=Workflow,
+ cast_to=WorkflowRetrieveResponse,
)
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,
+ 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,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Workflow, AsyncEntriesCursor[Workflow]]:
"""Returns a paginated list of workflows available in a given environment.
@@ -525,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.
@@ -552,6 +607,7 @@ def list(
"after": after,
"annotate": annotate,
"before": before,
+ "branch": branch,
"hide_uncommitted_changes": hide_uncommitted_changes,
"limit": limit,
},
@@ -567,12 +623,13 @@ 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,
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.
@@ -588,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
@@ -607,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,
@@ -618,17 +682,18 @@ async def run(
workflow_key: str,
*,
environment: str,
- recipients: List[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,
+ 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,
+ 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
@@ -639,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.
@@ -646,7 +714,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
@@ -675,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,
)
@@ -686,15 +760,16 @@ 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,
+ 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.
# The extra values given here take precedence over values defined on the client or passed to this 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
@@ -709,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`.
@@ -735,6 +813,7 @@ async def upsert(
{
"environment": environment,
"annotate": annotate,
+ "branch": branch,
"commit": commit,
"commit_message": commit_message,
},
@@ -750,12 +829,13 @@ 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,
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.
@@ -769,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
@@ -788,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/__init__.py b/src/knock_mapi/types/__init__.py
index 4356197..b46991e 100644
--- a/src/knock_mapi/types/__init__.py
+++ b/src/knock_mapi/types/__init__.py
@@ -2,6 +2,22 @@
from __future__ import annotations
+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
+from .branch import Branch as Branch
from .commit import Commit as Commit
from .shared import PageInfo as PageInfo
from .channel import Channel as Channel
@@ -9,7 +25,9 @@
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
from .send_window import SendWindow as SendWindow
from .translation import Translation as Translation
@@ -24,22 +42,32 @@
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 .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
+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
from .partial_list_params import PartialListParams as PartialListParams
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
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
@@ -47,39 +75,62 @@
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
+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
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
from .webhook_template_param import WebhookTemplateParam as WebhookTemplateParam
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
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
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
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
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 .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
@@ -88,7 +139,9 @@
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 .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
@@ -96,11 +149,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_channel_step_param import WorkflowChannelStepParam as WorkflowChannelStepParam
+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
@@ -112,5 +166,36 @@
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
+
+# 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_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
+ 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)
+ 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)
+ 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/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 4f2620c..36c691b 100644
--- a/src/knock_mapi/types/auth_verify_response.py
+++ b/src/knock_mapi/types/auth_verify_response.py
@@ -1,13 +1,97 @@
# 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"]
+__all__ = ["AuthVerifyResponse", "AccountFeatures"]
+
+
+class AccountFeatures(BaseModel):
+ """Account plan features and limits."""
+
+ 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."""
+
+ 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."""
+
+ 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):
+ """Information about the current calling scope."""
+
+ 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.
+ """
- service_token_name: str
+ user_id: Optional[str] = None
+ """
+ The ID of the authenticated user if in OAuth context, null for service token
+ contexts.
+ """
diff --git a/src/knock_mapi/types/branch.py b/src/knock_mapi/types/branch.py
new file mode 100644
index 0000000..b79bb5f
--- /dev/null
+++ b/src/knock_mapi/types/branch.py
@@ -0,0 +1,27 @@
+# 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):
+ """A branch object."""
+
+ 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/src/knock_mapi/types/broadcast.py b/src/knock_mapi/types/broadcast.py
new file mode 100644
index 0000000..18a986b
--- /dev/null
+++ b/src/knock_mapi/types/broadcast.py
@@ -0,0 +1,109 @@
+# 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):
+ """A map of broadcast settings."""
+
+ 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):
+ """A broadcast object."""
+
+ 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..9bd2565
--- /dev/null
+++ b/src/knock_mapi/types/broadcast_cancel_response.py
@@ -0,0 +1,17 @@
+# 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):
+ """Wraps the Broadcast response under the `broadcast` key."""
+
+ 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..37a076c
--- /dev/null
+++ b/src/knock_mapi/types/broadcast_request_param.py
@@ -0,0 +1,79 @@
+# 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):
+ """A map of broadcast settings."""
+
+ 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):
+ """A broadcast request for upserting a broadcast."""
+
+ 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..03f77ca
--- /dev/null
+++ b/src/knock_mapi/types/broadcast_send_response.py
@@ -0,0 +1,17 @@
+# 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):
+ """Wraps the Broadcast response under the `broadcast` key."""
+
+ 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..006457a
--- /dev/null
+++ b/src/knock_mapi/types/broadcast_upsert_response.py
@@ -0,0 +1,17 @@
+# 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):
+ """Wraps the Broadcast response under the `broadcast` key."""
+
+ 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..f5a7430
--- /dev/null
+++ b/src/knock_mapi/types/broadcast_validate_response.py
@@ -0,0 +1,17 @@
+# 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):
+ """Wraps the Broadcast response under the `broadcast` key."""
+
+ broadcast: "Broadcast"
+ """A broadcast object."""
+
+
+from .broadcast import Broadcast
diff --git a/src/knock_mapi/types/channel.py b/src/knock_mapi/types/channel.py
index 87fd918..87dd516 100644
--- a/src/knock_mapi/types/channel.py
+++ b/src/knock_mapi/types/channel.py
@@ -10,6 +10,11 @@
class Channel(BaseModel):
+ """A configured channel, which is a way to route messages to a provider."""
+
+ 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_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 993120f..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."""
@@ -43,6 +47,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/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/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 30ab531..198db35 100644
--- a/src/knock_mapi/types/commit.py
+++ b/src/knock_mapi/types/commit.py
@@ -6,10 +6,12 @@
from .._models import BaseModel
-__all__ = ["Commit", "CommitAuthor", "Resource"]
+__all__ = ["Commit", "Author", "Resource"]
-class CommitAuthor(BaseModel):
+class Author(BaseModel):
+ """The author of the commit."""
+
email: str
"""The email address of the commit author."""
@@ -18,23 +20,24 @@ class CommitAuthor(BaseModel):
class Resource(BaseModel):
+ """The resource object associated with the commit."""
+
identifier: str
"""The unique identifier for the resource."""
- type: Literal["email_layout", "workflow", "translation", "partial", "message_type"]
+ type: Literal["audience", "email_layout", "guide", "message_type", "partial", "translation", "workflow"]
"""The type of the resource object."""
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."""
- 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 +47,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."""
diff --git a/src/knock_mapi/types/commit_commit_all_params.py b/src/knock_mapi/types/commit_commit_all_params.py
index d5331d4..c1f1f63 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"]
@@ -11,5 +12,27 @@ 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."""
+
+ 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_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_list_params.py b/src/knock_mapi/types/commit_list_params.py
index 26b5b3c..ae8ada1 100644
--- a/src/knock_mapi/types/commit_list_params.py
+++ b/src/knock_mapi/types/commit_list_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__ = ["CommitListParams"]
@@ -17,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."""
@@ -25,3 +32,21 @@ 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: 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..3cb5201 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"]
@@ -17,5 +18,25 @@ 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.
+
+ 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/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 b5ee704..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",
@@ -19,6 +21,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_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 ad44a1a..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",
@@ -20,6 +22,7 @@ class ConditionParam(TypedDict, total=False):
"contains",
"not_contains",
"contains_all",
+ "not_contains_all",
"empty",
"not_empty",
"is_audience_member",
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_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..09a5eee 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."""
@@ -34,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 4a764cf..c15d316 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]
@@ -25,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
new file mode 100644
index 0000000..1924926
--- /dev/null
+++ b/src/knock_mapi/types/guide.py
@@ -0,0 +1,85 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from datetime import datetime
+
+from .._models import BaseModel
+from .guide_step import GuideStep
+from .condition_group import ConditionGroup
+from .guide_activation_url_pattern import GuideActivationURLPattern
+
+__all__ = ["Guide"]
+
+
+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."""
+
+ 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_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
+ """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.
+
+ 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.
+
+ 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
new file mode 100644
index 0000000..e1692ec
--- /dev/null
+++ b/src/knock_mapi/types/guide_activate_params.py
@@ -0,0 +1,53 @@
+# 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", "GuideBooleanActivationParams", "GuideScheduledActivationParams"]
+
+
+class GuideBooleanActivationParams(TypedDict, total=False):
+ environment: Required[str]
+ """The environment slug."""
+
+ 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.
+
+ 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[GuideBooleanActivationParams, GuideScheduledActivationParams]
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..fbf25fc
--- /dev/null
+++ b/src/knock_mapi/types/guide_activate_response.py
@@ -0,0 +1,16 @@
+# 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):
+ """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
+ and other conditions.
+ """
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..b28b672
--- /dev/null
+++ b/src/knock_mapi/types/guide_activation_url_pattern.py
@@ -0,0 +1,19 @@
+# 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):
+ """
+ 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."""
+
+ 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..b5c4e74
--- /dev/null
+++ b/src/knock_mapi/types/guide_activation_url_pattern_param.py
@@ -0,0 +1,19 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["GuideActivationURLPatternParam"]
+
+
+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."""
+
+ 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..e930e19
--- /dev/null
+++ b/src/knock_mapi/types/guide_archive_response.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["GuideArchiveResponse"]
+
+
+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_list_params.py b/src/knock_mapi/types/guide_list_params.py
new file mode 100644
index 0000000..0f49fe4
--- /dev/null
+++ b/src/knock_mapi/types/guide_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__ = ["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."""
+
+ 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/guide_retrieve_params.py b/src/knock_mapi/types/guide_retrieve_params.py
new file mode 100644
index 0000000..4f98219
--- /dev/null
+++ b/src/knock_mapi/types/guide_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__ = ["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."""
+
+ 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/guide_step.py b/src/knock_mapi/types/guide_step.py
new file mode 100644
index 0000000..6143cb4
--- /dev/null
+++ b/src/knock_mapi/types/guide_step.py
@@ -0,0 +1,36 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict, Optional
+
+from .._models import BaseModel
+
+__all__ = ["GuideStep"]
+
+
+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.
+
+ 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[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
new file mode 100644
index 0000000..e202de9
--- /dev/null
+++ b/src/knock_mapi/types/guide_step_param.py
@@ -0,0 +1,37 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict
+from typing_extensions import Required, TypedDict
+
+__all__ = ["GuideStepParam"]
+
+
+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.
+
+ 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: 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
new file mode 100644
index 0000000..fe79da0
--- /dev/null
+++ b/src/knock_mapi/types/guide_upsert_params.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, Optional
+from datetime import datetime
+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"]
+
+
+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."""
+
+ 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."""
+
+ commit_message: str
+ """The message to commit the resource with, only used if `commit` is `true`."""
+
+
+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."""
+
+ 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_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")]
+ """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.
+ """
+
+ target_audience_id: Optional[str]
+ """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."""
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..8c2957b
--- /dev/null
+++ b/src/knock_mapi/types/guide_upsert_response.py
@@ -0,0 +1,16 @@
+# 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):
+ """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
+ 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..77b2ab8
--- /dev/null
+++ b/src/knock_mapi/types/guide_validate_params.py
@@ -0,0 +1,66 @@
+# 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 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"]
+
+
+class GuideValidateParams(TypedDict, total=False):
+ environment: Required[str]
+ """The environment slug."""
+
+ 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):
+ """A request to create or update a guide."""
+
+ 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_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")]
+ """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.
+ """
+
+ target_audience_id: Optional[str]
+ """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."""
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..0ee351a
--- /dev/null
+++ b/src/knock_mapi/types/guide_validate_response.py
@@ -0,0 +1,16 @@
+# 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):
+ """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
+ and other conditions.
+ """
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_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_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 e8d98a5..3b3fc07 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."""
@@ -28,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 4b14a62..6574f8d 100644
--- a/src/knock_mapi/types/message_type_validate_params.py
+++ b/src/knock_mapi/types/message_type_validate_params.py
@@ -17,8 +17,16 @@ 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):
+ """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 1789081..b37c248 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__ = [
@@ -34,6 +35,8 @@
class FieldMessageTypeBooleanFieldSettings(TypedDict, total=False):
+ """Settings for the boolean field."""
+
default: bool
"""The default value of the boolean field."""
@@ -44,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."""
@@ -58,6 +63,8 @@ class FieldMessageTypeBooleanField(TypedDict, total=False):
class FieldMessageTypeButtonFieldSettings(TypedDict, total=False):
+ """Settings for the button field."""
+
description: str
required: bool
@@ -65,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."""
@@ -85,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."""
@@ -95,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."""
@@ -109,6 +122,8 @@ class FieldMessageTypeImageFieldURL(TypedDict, total=False):
class FieldMessageTypeImageFieldSettings(TypedDict, total=False):
+ """Settings for the image field."""
+
description: str
required: bool
@@ -116,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."""
@@ -139,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."""
@@ -149,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."""
@@ -171,7 +192,9 @@ class FieldMessageTypeMultiSelectFieldSettingsOption(TypedDict, total=False):
class FieldMessageTypeMultiSelectFieldSettings(TypedDict, total=False):
- default: Optional[List[str]]
+ """Settings for the multi_select field."""
+
+ default: Optional[SequenceNotStr[str]]
"""The default values for the multi-select field."""
description: str
@@ -184,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."""
@@ -206,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."""
@@ -219,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."""
@@ -233,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."""
@@ -247,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."""
@@ -261,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."""
@@ -271,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."""
@@ -298,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_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..00b1875 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."""
@@ -26,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 dde18a2..c102290 100644
--- a/src/knock_mapi/types/partial_validate_params.py
+++ b/src/knock_mapi/types/partial_validate_params.py
@@ -15,8 +15,16 @@ 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):
+ """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 9f420fa..feeb410 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."""
@@ -25,6 +25,8 @@ class QueryParam(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."""
@@ -34,14 +36,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..7ca91cc 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."""
@@ -25,6 +25,8 @@ class QueryParam(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."""
@@ -34,14 +36,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.
"""
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_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_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 a134c5d..86e96ea 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."""
@@ -37,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 ed32ad9..e926ed9 100644
--- a/src/knock_mapi/types/translation_validate_params.py
+++ b/src/knock_mapi/types/translation_validate_params.py
@@ -17,8 +17,18 @@ 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):
+ """
+ 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/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/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 25b2a92..e6079f3 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
@@ -14,6 +13,8 @@
class Settings(BaseModel):
+ """A map of workflow settings."""
+
is_commercial: Optional[bool] = None
"""Whether the workflow is commercial. Defaults to false."""
@@ -26,6 +27,8 @@ class Settings(BaseModel):
class Workflow(BaseModel):
+ """A workflow object."""
+
active: bool
"""
Whether the workflow is
@@ -101,10 +104,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_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_activate_response.py b/src/knock_mapi/types/workflow_activate_response.py
index dc6c7ec..a63e35d 100644
--- a/src/knock_mapi/types/workflow_activate_response.py
+++ b/src/knock_mapi/types/workflow_activate_response.py
@@ -2,20 +2,16 @@
from __future__ import annotations
-from .._compat import PYDANTIC_V2
from .._models import BaseModel
__all__ = ["WorkflowActivateResponse"]
class WorkflowActivateResponse(BaseModel):
+ """Wraps the Workflow response under the `workflow` key."""
+
workflow: "Workflow"
"""A workflow object."""
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_batch_step.py b/src/knock_mapi/types/workflow_batch_step.py
index edf6d17..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,15 +57,11 @@ class Settings(BaseModel):
class WorkflowBatchStep(BaseModel):
- description: Optional[str] = None
- """An arbitrary string attached to a workflow step.
+ """A batch function step.
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/batch-function).
"""
- name: str
- """A name for the workflow step."""
-
ref: str
"""The reference key of the workflow step. Must be unique per workflow."""
@@ -72,3 +70,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..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,15 +58,11 @@ class Settings(TypedDict, total=False):
class WorkflowBatchStepParam(TypedDict, total=False):
- description: Required[Optional[str]]
- """An arbitrary string attached to a workflow step.
+ """A batch function step.
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/batch-function).
"""
- 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 +71,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 b563ff0..5aa4d25 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
@@ -13,6 +12,8 @@
class Branch(BaseModel):
+ """A branch in a branch step."""
+
conditions: Optional[ConditionGroup] = None
"""A group of conditions to be evaluated."""
@@ -27,17 +28,13 @@ class Branch(BaseModel):
class WorkflowBranchStep(BaseModel):
- branches: List[Branch]
- """A list of workflow branches to be evaluated."""
-
- description: str
- """An arbitrary string attached to a workflow step.
+ """A branch function step.
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/branch-function).
"""
- name: str
- """A name for the workflow step."""
+ 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."""
@@ -45,12 +42,14 @@ class WorkflowBranchStep(BaseModel):
type: Literal["branch"]
"""The type of step."""
+ description: Optional[str] = None
+ """An arbitrary string attached to a workflow step.
-from .workflow_step import WorkflowStep
+ Useful for adding notes about the workflow for internal purposes.
+ """
-if PYDANTIC_V2:
- WorkflowBranchStep.model_rebuild()
- Branch.model_rebuild()
-else:
- WorkflowBranchStep.update_forward_refs() # type: ignore
- Branch.update_forward_refs() # type: ignore
+ name: Optional[str] = None
+ """A name for the workflow 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..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,17 +27,13 @@ class Branch(TypedDict, total=False):
class WorkflowBranchStepParam(TypedDict, total=False):
- branches: Required[Iterable[Branch]]
- """A list of workflow branches to be evaluated."""
-
- description: Required[str]
- """An arbitrary string attached to a workflow step.
+ """A branch function step.
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/branch-function).
"""
- name: Required[str]
- """A name for the workflow step."""
+ 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."""
@@ -43,5 +41,14 @@ class WorkflowBranchStepParam(TypedDict, total=False):
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: Optional[str]
+ """A name for the workflow step."""
+
from .workflow_step_param import WorkflowStepParam
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_chat_step.py b/src/knock_mapi/types/workflow_chat_step.py
new file mode 100644
index 0000000..904e950
--- /dev/null
+++ b/src/knock_mapi/types/workflow_chat_step.py
@@ -0,0 +1,69 @@
+# 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):
+ """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."""
+
+ 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.
+ """
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..57716e1
--- /dev/null
+++ b/src/knock_mapi/types/workflow_chat_step_param.py
@@ -0,0 +1,70 @@
+# 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):
+ """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."""
+
+ 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.
+ """
diff --git a/src/knock_mapi/types/workflow_delay_step.py b/src/knock_mapi/types/workflow_delay_step.py
index 3f3fe5a..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,18 +27,11 @@ class Settings(BaseModel):
class WorkflowDelayStep(BaseModel):
- conditions: Optional[ConditionGroup] = None
- """A group of conditions to be evaluated."""
+ """A delay function step.
- description: Optional[str] = None
- """An arbitrary string attached to a workflow step.
-
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/delay-function).
"""
- name: str
- """A name for the workflow step."""
-
ref: str
"""The reference key of the workflow step. Must be unique per workflow."""
@@ -46,3 +44,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..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,18 +28,11 @@ class Settings(TypedDict, total=False):
class WorkflowDelayStepParam(TypedDict, total=False):
- conditions: Required[Optional[ConditionGroupParam]]
- """A group of conditions to be evaluated."""
+ """A delay function step.
- description: Required[Optional[str]]
- """An arbitrary string attached to a workflow step.
-
- Useful for adding notes about the workflow for internal purposes.
+ Read more in the [docs](https://docs.knock.app/designing-workflows/delay-function).
"""
- 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 +45,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
new file mode 100644
index 0000000..c9a2dae
--- /dev/null
+++ b/src/knock_mapi/types/workflow_email_step.py
@@ -0,0 +1,69 @@
+# 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):
+ """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."""
+
+ 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.
+
+ 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..6b135cc
--- /dev/null
+++ b/src/knock_mapi/types/workflow_email_step_param.py
@@ -0,0 +1,70 @@
+# 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):
+ """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."""
+
+ 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.
+
+ 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 03e5a5a..0f1ef6d 100644
--- a/src/knock_mapi/types/workflow_fetch_step.py
+++ b/src/knock_mapi/types/workflow_fetch_step.py
@@ -11,8 +11,10 @@
class WorkflowFetchStep(BaseModel):
- name: str
- """A name for the workflow step."""
+ """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."""
@@ -20,7 +22,7 @@ class WorkflowFetchStep(BaseModel):
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 +33,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..468d52b 100644
--- a/src/knock_mapi/types/workflow_fetch_step_param.py
+++ b/src/knock_mapi/types/workflow_fetch_step_param.py
@@ -12,8 +12,10 @@
class WorkflowFetchStepParam(TypedDict, total=False):
- name: Required[str]
- """A name for the workflow step."""
+ """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."""
@@ -21,7 +23,7 @@ class WorkflowFetchStepParam(TypedDict, total=False):
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 +34,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_channel_step.py b/src/knock_mapi/types/workflow_in_app_feed_step.py
similarity index 52%
rename from src/knock_mapi/types/workflow_channel_step.py
rename to src/knock_mapi/types/workflow_in_app_feed_step.py
index 2f2e93a..8b2f5bb 100644
--- a/src/knock_mapi/types/workflow_channel_step.py
+++ b/src/knock_mapi/types/workflow_in_app_feed_step.py
@@ -1,46 +1,28 @@
# 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 typing import List, Optional
+from typing_extensions import Literal
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"]
+__all__ = ["WorkflowInAppFeedStep"]
-Template: TypeAlias = Union[EmailTemplate, InAppFeedTemplate, SMSTemplate, PushTemplate, ChatTemplate, WebhookTemplate]
-ChannelOverrides: TypeAlias = Union[
- EmailChannelSettings, InAppFeedChannelSettings, SMSChannelSettings, PushChannelSettings, ChatChannelSettings, None
-]
+class WorkflowInAppFeedStep(BaseModel):
+ """An in-app feed step within a workflow.
-
-class WorkflowChannelStep(BaseModel):
- name: str
- """A name for the workflow step."""
+ 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."""
- 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.
- """
+ template: InAppFeedTemplate
+ """An in-app feed template."""
type: Literal["channel"]
"""The type of the workflow step."""
@@ -59,8 +41,14 @@ class WorkflowChannelStep(BaseModel):
both.
"""
- channel_overrides: Optional[ChannelOverrides] = None
- """A map of channel overrides for the channel step."""
+ channel_overrides: Optional[InAppFeedChannelSettings] = None
+ """In-app feed channel settings.
+
+ 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."""
@@ -71,6 +59,9 @@ class WorkflowChannelStep(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
new file mode 100644
index 0000000..2056690
--- /dev/null
+++ b/src/knock_mapi/types/workflow_in_app_feed_step_param.py
@@ -0,0 +1,70 @@
+# 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):
+ """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."""
+
+ 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.
+ """
+
+ 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."""
+
+ 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.
+ """
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_push_step.py b/src/knock_mapi/types/workflow_push_step.py
new file mode 100644
index 0000000..20873ae
--- /dev/null
+++ b/src/knock_mapi/types/workflow_push_step.py
@@ -0,0 +1,69 @@
+# 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):
+ """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."""
+
+ 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.
+ """
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..e303484
--- /dev/null
+++ b/src/knock_mapi/types/workflow_push_step_param.py
@@ -0,0 +1,70 @@
+# 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):
+ """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."""
+
+ 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.
+ """
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_retrieve_response.py b/src/knock_mapi/types/workflow_retrieve_response.py
new file mode 100644
index 0000000..701f8b0
--- /dev/null
+++ b/src/knock_mapi/types/workflow_retrieve_response.py
@@ -0,0 +1,138 @@
+# 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):
+ """User information."""
+
+ 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):
+ """A map of workflow settings."""
+
+ 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):
+ """User information."""
+
+ 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):
+ """A workflow object."""
+
+ 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/src/knock_mapi/types/workflow_run_params.py b/src/knock_mapi/types/workflow_run_params.py
index 62e63e4..e1ebc15 100644
--- a/src/knock_mapi/types/workflow_run_params.py
+++ b/src/knock_mapi/types/workflow_run_params.py
@@ -2,19 +2,33 @@
from __future__ import annotations
-from typing import Dict, List, Union, Optional
+from typing import Dict, Union, Optional
from typing_extensions import Required, TypeAlias, TypedDict
-__all__ = ["WorkflowRunParams", "Recipient", "RecipientUnionMember1", "Actor", "ActorUnionMember1"]
+from .._types import SequenceNotStr
+
+__all__ = [
+ "WorkflowRunParams",
+ "Recipient",
+ "RecipientObjectRecipientReference",
+ "Actor",
+ "ActorObjectRecipientReference",
+]
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."""
+ 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
@@ -28,22 +42,30 @@ 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):
+ """An object reference."""
-class RecipientUnionMember1(TypedDict, total=False):
id: Required[str]
+ """The ID of the object."""
collection: Required[str]
+ """The collection of the object."""
+
+Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference]
-Recipient: TypeAlias = Union[str, RecipientUnionMember1]
+class ActorObjectRecipientReference(TypedDict, total=False):
+ """An object reference."""
-class ActorUnionMember1(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/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
new file mode 100644
index 0000000..9dd23fc
--- /dev/null
+++ b/src/knock_mapi/types/workflow_sms_step.py
@@ -0,0 +1,69 @@
+# 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):
+ """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."""
+
+ 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.
+ """
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..f8fb916
--- /dev/null
+++ b/src/knock_mapi/types/workflow_sms_step_param.py
@@ -0,0 +1,70 @@
+# 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):
+ """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."""
+
+ 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.
+ """
diff --git a/src/knock_mapi/types/workflow_step.py b/src/knock_mapi/types/workflow_step.py
index f6ee72a..ab3501a 100644
--- a/src/knock_mapi/types/workflow_step.py
+++ b/src/knock_mapi/types/workflow_step.py
@@ -5,21 +5,31 @@
from typing import TYPE_CHECKING, Union
from typing_extensions import TypeAlias, TypeAliasType
-from .._compat import PYDANTIC_V2
+from .._compat import PYDANTIC_V1
+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 .workflow_channel_step import WorkflowChannelStep
+from .workflow_webhook_step import WorkflowWebhookStep
from .workflow_throttle_step import WorkflowThrottleStep
+from .workflow_in_app_feed_step import WorkflowInAppFeedStep
from .workflow_trigger_workflow_step import WorkflowTriggerWorkflowStep
__all__ = ["WorkflowStep"]
-if TYPE_CHECKING or PYDANTIC_V2:
+if TYPE_CHECKING or not PYDANTIC_V1:
WorkflowStep = TypeAliasType(
"WorkflowStep",
Union[
- WorkflowChannelStep,
+ WorkflowWebhookStep,
+ WorkflowInAppFeedStep,
+ WorkflowChatStep,
+ WorkflowSMSStep,
+ WorkflowPushStep,
+ WorkflowEmailStep,
WorkflowDelayStep,
WorkflowBatchStep,
WorkflowFetchStep,
@@ -30,7 +40,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 52d5618..b8443f4 100644
--- a/src/knock_mapi/types/workflow_step_param.py
+++ b/src/knock_mapi/types/workflow_step_param.py
@@ -5,21 +5,31 @@
from typing import TYPE_CHECKING, Union
from typing_extensions import TypeAlias, TypeAliasType
-from .._compat import PYDANTIC_V2
+from .._compat import PYDANTIC_V1
+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 .workflow_channel_step_param import WorkflowChannelStepParam
+from .workflow_webhook_step_param import WorkflowWebhookStepParam
from .workflow_throttle_step_param import WorkflowThrottleStepParam
+from .workflow_in_app_feed_step_param import WorkflowInAppFeedStepParam
from .workflow_trigger_workflow_step_param import WorkflowTriggerWorkflowStepParam
__all__ = ["WorkflowStepParam"]
-if TYPE_CHECKING or PYDANTIC_V2:
+if TYPE_CHECKING or not PYDANTIC_V1:
WorkflowStepParam = TypeAliasType(
"WorkflowStepParam",
Union[
- WorkflowChannelStepParam,
+ WorkflowWebhookStepParam,
+ WorkflowInAppFeedStepParam,
+ WorkflowChatStepParam,
+ WorkflowSMSStepParam,
+ WorkflowPushStepParam,
+ WorkflowEmailStepParam,
WorkflowDelayStepParam,
WorkflowBatchStepParam,
WorkflowFetchStepParam,
@@ -30,7 +40,12 @@
)
else:
WorkflowStepParam: TypeAlias = Union[
- WorkflowChannelStepParam,
+ WorkflowWebhookStepParam,
+ WorkflowInAppFeedStepParam,
+ 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 74f7e98..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,8 +34,10 @@ class Settings(BaseModel):
class WorkflowThrottleStep(BaseModel):
- name: str
- """A name for the workflow step."""
+ """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."""
@@ -52,3 +56,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..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,8 +35,10 @@ class Settings(TypedDict, total=False):
class WorkflowThrottleStepParam(TypedDict, total=False):
- name: Required[str]
- """A name for the workflow step."""
+ """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."""
@@ -53,3 +57,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..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,8 +32,10 @@ class Settings(BaseModel):
class WorkflowTriggerWorkflowStep(BaseModel):
- name: str
- """A name for the workflow step."""
+ """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."""
@@ -47,3 +51,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..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,8 +33,10 @@ class Settings(TypedDict, total=False):
class WorkflowTriggerWorkflowStepParam(TypedDict, total=False):
- name: Required[str]
- """A name for the workflow step."""
+ """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."""
@@ -46,5 +50,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_upsert_params.py b/src/knock_mapi/types/workflow_upsert_params.py
index d4dc8db..ee15bff 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"]
@@ -20,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."""
@@ -28,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."""
@@ -40,13 +49,15 @@ 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."""
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_upsert_response.py b/src/knock_mapi/types/workflow_upsert_response.py
index f7bea7c..a550a4b 100644
--- a/src/knock_mapi/types/workflow_upsert_response.py
+++ b/src/knock_mapi/types/workflow_upsert_response.py
@@ -2,20 +2,16 @@
from __future__ import annotations
-from .._compat import PYDANTIC_V2
from .._models import BaseModel
__all__ = ["WorkflowUpsertResponse"]
class WorkflowUpsertResponse(BaseModel):
+ """Wraps the Workflow response under the `workflow` key."""
+
workflow: "Workflow"
"""A workflow object."""
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_params.py b/src/knock_mapi/types/workflow_validate_params.py
index 896e83f..d4599d9 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"]
@@ -17,8 +18,16 @@ 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):
+ """A map of workflow settings."""
+
is_commercial: bool
"""Whether the workflow is commercial. Defaults to false."""
@@ -31,13 +40,15 @@ 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."""
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_response.py b/src/knock_mapi/types/workflow_validate_response.py
index f494e9b..f99bd30 100644
--- a/src/knock_mapi/types/workflow_validate_response.py
+++ b/src/knock_mapi/types/workflow_validate_response.py
@@ -2,20 +2,16 @@
from __future__ import annotations
-from .._compat import PYDANTIC_V2
from .._models import BaseModel
__all__ = ["WorkflowValidateResponse"]
class WorkflowValidateResponse(BaseModel):
+ """Wraps the Workflow response under the `workflow` key."""
+
workflow: "Workflow"
"""A workflow object."""
from .workflow import Workflow
-
-if PYDANTIC_V2:
- WorkflowValidateResponse.model_rebuild()
-else:
- WorkflowValidateResponse.update_forward_refs() # type: ignore
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..40395fc
--- /dev/null
+++ b/src/knock_mapi/types/workflow_webhook_step.py
@@ -0,0 +1,66 @@
+# 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):
+ """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."""
+
+ 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
+ """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.
+ """
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..01b2c89
--- /dev/null
+++ b/src/knock_mapi/types/workflow_webhook_step_param.py
@@ -0,0 +1,67 @@
+# 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):
+ """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."""
+
+ 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]
+ """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.
+ """
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..70e958a 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):
@@ -20,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
@@ -30,22 +42,30 @@ 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 RecipientUnionMember1(TypedDict, total=False):
+class RecipientObjectRecipientReference(TypedDict, total=False):
+ """An object reference."""
+
id: Required[str]
+ """The ID of the object."""
collection: Required[str]
+ """The collection of the object."""
+
+Recipient: TypeAlias = Union[str, RecipientObjectRecipientReference]
-Recipient: TypeAlias = Union[str, RecipientUnionMember1]
+class ActorObjectRecipientReference(TypedDict, total=False):
+ """An object reference."""
-class ActorUnionMember1(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_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."""
diff --git a/tests/api_resources/test_api_keys.py b/tests/api_resources/test_api_keys.py
index bf8cf39..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(
@@ -59,11 +53,11 @@ def test_streaming_response_exchange(self, client: KnockMgmt) -> None:
class TestAsyncAPIKeys:
- parametrize = pytest.mark.parametrize("async_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 = 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_exchange(self, async_client: AsyncKnockMgmt) -> None:
api_key = await async_client.api_keys.exchange(
@@ -71,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(
@@ -85,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 318b4c2..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:
@@ -53,19 +47,17 @@ def test_streaming_response_verify(self, client: KnockMgmt) -> None:
class TestAsyncAuth:
- parametrize = pytest.mark.parametrize("async_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 = 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_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()
@@ -75,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_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",
+ )
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",
+ }
+ ],
+ },
+ )
diff --git a/tests/api_resources/test_channel_groups.py b/tests/api_resources/test_channel_groups.py
index 7a32416..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:
@@ -66,19 +58,17 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None:
class TestAsyncChannelGroups:
- parametrize = pytest.mark.parametrize("async_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 = 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_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(
@@ -88,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()
@@ -100,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 3c22778..3b7f9d1 100644
--- a/tests/api_resources/test_channels.py
+++ b/tests/api_resources/test_channels.py
@@ -18,29 +18,24 @@
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(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
after="after",
before="before",
limit=0,
)
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 +45,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:
@@ -66,31 +59,28 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None:
class TestAsyncChannels:
- parametrize = pytest.mark.parametrize("async_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 = 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_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(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
after="after",
before="before",
limit=0,
)
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()
@@ -100,9 +90,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 368fb3a..00544c7 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,23 +73,22 @@ 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(
environment="development",
after="after",
before="before",
+ branch="feature-branch",
limit=0,
promoted=True,
+ resource_id="resource_id",
+ resource_type="audience",
)
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 +100,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 +114,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,20 +122,19 @@ 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(
environment="development",
+ branch="feature-branch",
commit_message="commit_message",
+ resource_id="resource_id",
+ resource_type="audience",
)
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 +146,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 +160,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 +168,18 @@ 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_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",
+ )
+ 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:
response = client.commits.with_raw_response.promote_all(
@@ -202,9 +191,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 +205,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 +213,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 +225,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 +239,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 ''"):
@@ -270,11 +249,11 @@ 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"])
-
- @pytest.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 = 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:
commit = await async_client.commits.retrieve(
@@ -282,9 +261,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(
@@ -296,9 +273,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(
@@ -312,9 +287,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 ''"):
@@ -322,9 +295,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(
@@ -332,23 +303,22 @@ 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(
environment="development",
after="after",
before="before",
+ branch="feature-branch",
limit=0,
promoted=True,
+ resource_id="resource_id",
+ resource_type="audience",
)
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(
@@ -360,9 +330,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(
@@ -376,9 +344,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(
@@ -386,20 +352,19 @@ 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(
environment="development",
+ branch="feature-branch",
commit_message="commit_message",
+ resource_id="resource_id",
+ resource_type="audience",
)
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(
@@ -411,9 +376,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(
@@ -427,9 +390,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(
@@ -437,9 +398,18 @@ 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_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",
+ )
+ 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:
response = await async_client.commits.with_raw_response.promote_all(
@@ -451,9 +421,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(
@@ -467,9 +435,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(
@@ -477,9 +443,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(
@@ -491,9 +455,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(
@@ -507,9 +469,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 f9c92b1..46e772d 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,22 +31,19 @@ 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(
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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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 +56,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 +71,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 +80,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 +88,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(
@@ -109,14 +96,13 @@ 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,
)
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 +114,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 +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_upsert(self, client: KnockMgmt) -> None:
email_layout = client.email_layouts.upsert(
@@ -160,9 +142,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(
@@ -180,14 +160,13 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None:
],
},
annotate=True,
+ branch="feature-branch",
commit=True,
commit_message="commit_message",
)
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 +184,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 +204,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 +218,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 +232,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(
@@ -278,12 +249,11 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None:
}
],
},
+ branch="feature-branch",
)
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 +271,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 +291,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 ''"):
@@ -341,11 +307,11 @@ def test_path_params_validate(self, client: KnockMgmt) -> None:
class TestAsyncEmailLayouts:
- parametrize = pytest.mark.parametrize("async_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 = 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:
email_layout = await async_client.email_layouts.retrieve(
@@ -354,22 +320,19 @@ 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(
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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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(
@@ -382,9 +345,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(
@@ -399,9 +360,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 ''"):
@@ -410,9 +369,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(
@@ -420,9 +377,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(
@@ -430,14 +385,13 @@ 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,
)
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(
@@ -449,9 +403,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(
@@ -465,9 +417,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(
@@ -481,9 +431,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(
@@ -501,14 +449,13 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt)
],
},
annotate=True,
+ branch="feature-branch",
commit=True,
commit_message="commit_message",
)
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(
@@ -526,9 +473,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(
@@ -548,9 +493,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 ''"):
@@ -564,9 +507,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(
@@ -580,9 +521,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(
@@ -599,12 +538,11 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm
}
],
},
+ branch="feature-branch",
)
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(
@@ -622,9 +560,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(
@@ -644,9 +580,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 560f10b..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:
@@ -116,11 +100,11 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None:
class TestAsyncEnvironments:
- parametrize = pytest.mark.parametrize("async_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 = 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:
environment = await async_client.environments.retrieve(
@@ -128,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(
@@ -142,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(
@@ -158,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 ''"):
@@ -168,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(
@@ -188,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()
@@ -200,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
new file mode 100644
index 0000000..1044e06
--- /dev/null
+++ b/tests/api_resources/test_guides.py
@@ -0,0 +1,1120 @@
+# 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,
+ GuideArchiveResponse,
+ 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="Prism doesn't support callbacks yet")
+ @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="Prism doesn't support callbacks yet")
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: KnockMgmt) -> None:
+ guide = client.guides.retrieve(
+ guide_key="guide_key",
+ environment="development",
+ annotate=True,
+ branch="feature-branch",
+ hide_uncommitted_changes=True,
+ )
+ assert_matches_type(Guide, guide, path=["response"])
+
+ @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(
+ 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="Prism doesn't support callbacks yet")
+ @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="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 ''"):
+ client.guides.with_raw_response.retrieve(
+ guide_key="",
+ environment="development",
+ )
+
+ @pytest.mark.skip(reason="Prism doesn't support callbacks yet")
+ @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="Prism doesn't support callbacks yet")
+ @parametrize
+ def test_method_list_with_all_params(self, client: KnockMgmt) -> None:
+ guide = client.guides.list(
+ environment="development",
+ after="after",
+ annotate=True,
+ before="before",
+ branch="feature-branch",
+ hide_uncommitted_changes=True,
+ limit=0,
+ )
+ assert_matches_type(SyncEntriesCursor[Guide], guide, path=["response"])
+
+ @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(
+ 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="Prism doesn't support callbacks yet")
+ @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="Prism doesn't support callbacks yet")
+ @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="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:
+ 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="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(
+ 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="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 ''"):
+ client.guides.with_raw_response.activate(
+ guide_key="",
+ environment="development",
+ status=True,
+ )
+
+ @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(
+ guide_key="guide_key",
+ environment="development",
+ )
+ 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_2(self, client: KnockMgmt) -> None:
+ 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"),
+ )
+ assert_matches_type(GuideActivateResponse, guide, path=["response"])
+
+ @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(
+ 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="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(
+ 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="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 ''"):
+ client.guides.with_raw_response.activate(
+ guide_key="",
+ 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:
+ 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="Prism doesn't support callbacks yet")
+ @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": "bar"},
+ }
+ ],
+ "activation_url_patterns": [
+ {
+ "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",
+ "target_audience_id": None,
+ "target_property_conditions": {
+ "all": [
+ {
+ "operator": "equal_to",
+ "variable": "recipient.property",
+ "argument": "some_property",
+ }
+ ]
+ },
+ },
+ annotate=True,
+ branch="feature-branch",
+ commit=True,
+ commit_message="commit_message",
+ )
+ assert_matches_type(GuideUpsertResponse, guide, path=["response"])
+
+ @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(
+ 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="Prism doesn't support callbacks yet")
+ @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="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 ''"):
+ 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="Prism doesn't support callbacks yet")
+ @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="Prism doesn't support callbacks yet")
+ @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": "bar"},
+ }
+ ],
+ "activation_url_patterns": [
+ {
+ "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",
+ "target_audience_id": None,
+ "target_property_conditions": {
+ "all": [
+ {
+ "operator": "equal_to",
+ "variable": "recipient.property",
+ "argument": "some_property",
+ }
+ ]
+ },
+ },
+ branch="feature-branch",
+ )
+ assert_matches_type(GuideValidateResponse, guide, path=["response"])
+
+ @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(
+ 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="Prism doesn't support callbacks yet")
+ @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="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 ''"):
+ 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="Prism doesn't support callbacks yet")
+ @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="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(
+ guide_key="guide_key",
+ environment="development",
+ annotate=True,
+ branch="feature-branch",
+ hide_uncommitted_changes=True,
+ )
+ assert_matches_type(Guide, guide, 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.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="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(
+ 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="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 ''"):
+ await async_client.guides.with_raw_response.retrieve(
+ guide_key="",
+ environment="development",
+ )
+
+ @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(
+ environment="development",
+ )
+ assert_matches_type(AsyncEntriesCursor[Guide], guide, 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:
+ guide = await async_client.guides.list(
+ environment="development",
+ after="after",
+ annotate=True,
+ before="before",
+ branch="feature-branch",
+ hide_uncommitted_changes=True,
+ limit=0,
+ )
+ assert_matches_type(AsyncEntriesCursor[Guide], guide, 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.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="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(
+ 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="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(
+ guide_key="guide_key",
+ environment="development",
+ status=True,
+ )
+ 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:
+ 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="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(
+ 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="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 ''"):
+ await async_client.guides.with_raw_response.activate(
+ guide_key="",
+ environment="development",
+ status=True,
+ )
+
+ @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(
+ guide_key="guide_key",
+ environment="development",
+ )
+ 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_2(self, async_client: AsyncKnockMgmt) -> None:
+ 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"),
+ )
+ 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_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="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(
+ 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="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 ''"):
+ await async_client.guides.with_raw_response.activate(
+ guide_key="",
+ 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:
+ 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="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(
+ 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": "bar"},
+ }
+ ],
+ "activation_url_patterns": [
+ {
+ "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",
+ "target_audience_id": None,
+ "target_property_conditions": {
+ "all": [
+ {
+ "operator": "equal_to",
+ "variable": "recipient.property",
+ "argument": "some_property",
+ }
+ ]
+ },
+ },
+ annotate=True,
+ branch="feature-branch",
+ commit=True,
+ commit_message="commit_message",
+ )
+ assert_matches_type(GuideUpsertResponse, guide, 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.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="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(
+ 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="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 ''"):
+ 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="Prism doesn't support callbacks yet")
+ @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="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(
+ 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": "bar"},
+ }
+ ],
+ "activation_url_patterns": [
+ {
+ "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",
+ "target_audience_id": None,
+ "target_property_conditions": {
+ "all": [
+ {
+ "operator": "equal_to",
+ "variable": "recipient.property",
+ "argument": "some_property",
+ }
+ ]
+ },
+ },
+ branch="feature-branch",
+ )
+ assert_matches_type(GuideValidateResponse, guide, 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.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="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(
+ 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="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 ''"):
+ 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",
+ }
+ ],
+ },
+ )
diff --git a/tests/api_resources/test_message_types.py b/tests/api_resources/test_message_types.py
index 70990d1..d9a583c 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,22 +31,19 @@ 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(
message_type_key="email",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
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 +56,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 +71,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 +80,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 +88,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(
@@ -109,14 +96,13 @@ 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,
)
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 +114,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 +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_upsert(self, client: KnockMgmt) -> None:
message_type = client.message_types.upsert(
@@ -160,9 +142,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(
@@ -196,14 +176,13 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None:
],
},
annotate=True,
+ branch="feature-branch",
commit=True,
commit_message="commit_message",
)
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 +200,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 +220,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 +234,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 +248,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(
@@ -310,12 +281,11 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None:
}
],
},
+ branch="feature-branch",
)
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 +303,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 +323,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 ''"):
@@ -373,11 +339,11 @@ def test_path_params_validate(self, client: KnockMgmt) -> None:
class TestAsyncMessageTypes:
- parametrize = pytest.mark.parametrize("async_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 = 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:
message_type = await async_client.message_types.retrieve(
@@ -386,22 +352,19 @@ 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(
message_type_key="email",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
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(
@@ -414,9 +377,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(
@@ -431,9 +392,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 ''"):
@@ -442,9 +401,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(
@@ -452,9 +409,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(
@@ -462,14 +417,13 @@ 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,
)
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(
@@ -481,9 +435,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(
@@ -497,9 +449,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(
@@ -513,9 +463,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(
@@ -549,14 +497,13 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt)
],
},
annotate=True,
+ branch="feature-branch",
commit=True,
commit_message="commit_message",
)
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(
@@ -574,9 +521,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(
@@ -596,9 +541,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 ''"):
@@ -612,9 +555,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(
@@ -628,9 +569,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(
@@ -663,12 +602,11 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm
}
],
},
+ branch="feature-branch",
)
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(
@@ -686,9 +624,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(
@@ -708,9 +644,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 c8c2c0e..6890b37 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,22 +31,19 @@ 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(
partial_key="partial_key",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
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 +56,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 +71,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 +80,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 +88,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(
@@ -109,14 +96,13 @@ 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,
)
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 +114,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 +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_upsert(self, client: KnockMgmt) -> None:
partial = client.partials.upsert(
@@ -160,9 +142,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(
@@ -177,14 +157,13 @@ 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",
)
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 +181,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 +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 `partial_key` but received ''"):
@@ -240,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:
partial = client.partials.validate(
@@ -256,9 +229,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(
@@ -272,12 +243,11 @@ 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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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 +265,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 +285,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 ''"):
@@ -335,11 +301,11 @@ def test_path_params_validate(self, client: KnockMgmt) -> None:
class TestAsyncPartials:
- parametrize = pytest.mark.parametrize("async_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 = 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:
partial = await async_client.partials.retrieve(
@@ -348,22 +314,19 @@ 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(
partial_key="partial_key",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
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(
@@ -376,9 +339,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(
@@ -393,9 +354,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 ''"):
@@ -404,9 +363,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(
@@ -414,9 +371,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(
@@ -424,14 +379,13 @@ 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,
)
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(
@@ -443,9 +397,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(
@@ -459,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:
partial = await async_client.partials.upsert(
@@ -475,9 +425,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(
@@ -492,14 +440,13 @@ 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",
)
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(
@@ -517,9 +464,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(
@@ -539,9 +484,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 ''"):
@@ -555,9 +498,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(
@@ -571,9 +512,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(
@@ -587,12 +526,11 @@ 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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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(
@@ -610,9 +548,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(
@@ -632,9 +568,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 3320481..c3f712a 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,24 +32,21 @@ 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(
locale_code="locale_code",
environment="development",
annotate=True,
+ branch="feature-branch",
format="json",
hide_uncommitted_changes=True,
namespace="namespace",
)
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 +59,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 +74,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 +83,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 +91,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(
@@ -112,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,
@@ -120,9 +108,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 +120,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 +134,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 +148,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(
@@ -180,15 +160,14 @@ 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",
)
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 +185,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 +205,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 +219,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 +232,21 @@ 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_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:
response = client.translations.with_raw_response.validate(
@@ -278,9 +263,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 +282,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 ''"):
@@ -316,11 +297,11 @@ def test_path_params_validate(self, client: KnockMgmt) -> None:
class TestAsyncTranslations:
- parametrize = pytest.mark.parametrize("async_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 = 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:
translation = await async_client.translations.retrieve(
@@ -329,24 +310,21 @@ 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(
locale_code="locale_code",
environment="development",
annotate=True,
+ branch="feature-branch",
format="json",
hide_uncommitted_changes=True,
namespace="namespace",
)
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(
@@ -359,9 +337,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(
@@ -376,9 +352,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 ''"):
@@ -387,9 +361,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(
@@ -397,9 +369,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(
@@ -407,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,
@@ -415,9 +386,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(
@@ -429,9 +398,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(
@@ -445,9 +412,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(
@@ -461,9 +426,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(
@@ -475,15 +438,14 @@ 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",
)
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(
@@ -501,9 +463,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(
@@ -523,9 +483,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 ''"):
@@ -539,9 +497,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(
@@ -554,9 +510,21 @@ 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_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:
response = await async_client.translations.with_raw_response.validate(
@@ -573,9 +541,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(
@@ -594,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 `locale_code` but received ''"):
diff --git a/tests/api_resources/test_variables.py b/tests/api_resources/test_variables.py
index c3eeb56..51d3646 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,22 +26,19 @@ 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(
environment="development",
after="after",
before="before",
+ branch="feature-branch",
limit=0,
)
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 +50,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(
@@ -73,11 +66,11 @@ def test_streaming_response_list(self, client: KnockMgmt) -> None:
class TestAsyncVariables:
- parametrize = pytest.mark.parametrize("async_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 = 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_list(self, async_client: AsyncKnockMgmt) -> None:
variable = await async_client.variables.list(
@@ -85,22 +78,19 @@ 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(
environment="development",
after="after",
before="before",
+ branch="feature-branch",
limit=0,
)
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(
@@ -112,9 +102,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 497a224..8f57aae 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
@@ -24,33 +25,28 @@
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(
workflow_key="workflow_key",
environment="development",
)
- assert_matches_type(Workflow, workflow, path=["response"])
+ assert_matches_type(WorkflowRetrieveResponse, 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(
workflow_key="workflow_key",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
- assert_matches_type(Workflow, workflow, path=["response"])
+ assert_matches_type(WorkflowRetrieveResponse, 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(
@@ -61,11 +57,9 @@ 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="currently no good way to test endpoints defining 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(
@@ -76,13 +70,11 @@ 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
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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 +83,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 +91,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(
@@ -111,14 +99,13 @@ 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,
)
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 +117,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 +131,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 +141,18 @@ 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_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:
response = client.workflows.with_raw_response.activate(
@@ -174,9 +166,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 +182,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 +192,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,15 +202,14 @@ 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(
workflow_key="workflow_key",
environment="development",
recipients=["dnedry"],
+ branch="feature-branch",
actor={
"id": "project_1",
"collection": "projects",
@@ -235,9 +220,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 +234,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 +250,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 +260,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(
@@ -293,7 +270,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",
@@ -303,9 +279,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(
@@ -315,7 +289,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 }}**",
@@ -328,19 +301,10 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None:
"action_url": "{{ vars.app_url }}",
},
"type": "channel",
- "channel_group_key": "email",
+ "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},
+ "channel_type": "in_app_feed",
"conditions": {
"all": [
{
@@ -350,13 +314,14 @@ def test_method_upsert_with_all_params(self, client: KnockMgmt) -> None:
}
]
},
- "description": "Delay for 10 seconds",
+ "description": "This is a description of the channel step",
+ "name": "Channel 1",
"send_windows": [
{
"day": "monday",
"type": "send",
- "from": "from",
- "until": "until",
+ "from": "18:11:19.117Z",
+ "until": "18:11:19.117Z",
}
],
}
@@ -380,14 +345,13 @@ 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",
)
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(
@@ -397,7 +361,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",
@@ -411,9 +374,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(
@@ -423,7 +384,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",
@@ -439,9 +399,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 ''"):
@@ -452,7 +410,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",
@@ -461,9 +418,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(
@@ -473,7 +428,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",
@@ -483,9 +437,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(
@@ -495,7 +447,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 }}**",
@@ -508,19 +459,10 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None:
"action_url": "{{ vars.app_url }}",
},
"type": "channel",
- "channel_group_key": "email",
+ "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},
+ "channel_type": "in_app_feed",
"conditions": {
"all": [
{
@@ -530,13 +472,14 @@ def test_method_validate_with_all_params(self, client: KnockMgmt) -> None:
}
]
},
- "description": "Delay for 10 seconds",
+ "description": "This is a description of the channel step",
+ "name": "Channel 1",
"send_windows": [
{
"day": "monday",
"type": "send",
- "from": "from",
- "until": "until",
+ "from": "18:11:19.117Z",
+ "until": "18:11:19.117Z",
}
],
}
@@ -559,12 +502,11 @@ 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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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(
@@ -574,7 +516,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",
@@ -588,9 +529,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(
@@ -600,7 +539,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",
@@ -616,9 +554,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 ''"):
@@ -629,7 +565,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",
@@ -640,35 +575,32 @@ def test_path_params_validate(self, client: KnockMgmt) -> None:
class TestAsyncWorkflows:
- parametrize = pytest.mark.parametrize("async_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 = 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:
workflow = await async_client.workflows.retrieve(
workflow_key="workflow_key",
environment="development",
)
- assert_matches_type(Workflow, workflow, path=["response"])
+ assert_matches_type(WorkflowRetrieveResponse, 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(
workflow_key="workflow_key",
environment="development",
annotate=True,
+ branch="feature-branch",
hide_uncommitted_changes=True,
)
- assert_matches_type(Workflow, workflow, path=["response"])
+ assert_matches_type(WorkflowRetrieveResponse, 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(
@@ -679,11 +611,9 @@ 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="currently no good way to test endpoints defining 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(
@@ -694,13 +624,11 @@ 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
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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 ''"):
@@ -709,9 +637,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(
@@ -719,9 +645,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(
@@ -729,14 +653,13 @@ 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,
)
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(
@@ -748,9 +671,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(
@@ -764,9 +685,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(
@@ -776,9 +695,18 @@ 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_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:
response = await async_client.workflows.with_raw_response.activate(
@@ -792,9 +720,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(
@@ -810,9 +736,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 ''"):
@@ -822,9 +746,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(
@@ -834,15 +756,14 @@ 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(
workflow_key="workflow_key",
environment="development",
recipients=["dnedry"],
+ branch="feature-branch",
actor={
"id": "project_1",
"collection": "projects",
@@ -853,9 +774,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(
@@ -869,9 +788,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(
@@ -887,9 +804,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 ''"):
@@ -899,9 +814,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(
@@ -911,7 +824,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",
@@ -921,9 +833,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(
@@ -933,7 +843,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 }}**",
@@ -946,19 +855,10 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt)
"action_url": "{{ vars.app_url }}",
},
"type": "channel",
- "channel_group_key": "email",
+ "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},
+ "channel_type": "in_app_feed",
"conditions": {
"all": [
{
@@ -968,13 +868,14 @@ async def test_method_upsert_with_all_params(self, async_client: AsyncKnockMgmt)
}
]
},
- "description": "Delay for 10 seconds",
+ "description": "This is a description of the channel step",
+ "name": "Channel 1",
"send_windows": [
{
"day": "monday",
"type": "send",
- "from": "from",
- "until": "until",
+ "from": "18:11:19.117Z",
+ "until": "18:11:19.117Z",
}
],
}
@@ -998,14 +899,13 @@ 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",
)
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(
@@ -1015,7 +915,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",
@@ -1029,9 +928,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(
@@ -1041,7 +938,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",
@@ -1057,9 +953,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 ''"):
@@ -1070,7 +964,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",
@@ -1079,9 +972,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(
@@ -1091,7 +982,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",
@@ -1101,9 +991,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(
@@ -1113,7 +1001,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 }}**",
@@ -1126,19 +1013,10 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm
"action_url": "{{ vars.app_url }}",
},
"type": "channel",
- "channel_group_key": "email",
+ "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},
+ "channel_type": "in_app_feed",
"conditions": {
"all": [
{
@@ -1148,13 +1026,14 @@ async def test_method_validate_with_all_params(self, async_client: AsyncKnockMgm
}
]
},
- "description": "Delay for 10 seconds",
+ "description": "This is a description of the channel step",
+ "name": "Channel 1",
"send_windows": [
{
"day": "monday",
"type": "send",
- "from": "from",
- "until": "until",
+ "from": "18:11:19.117Z",
+ "until": "18:11:19.117Z",
}
],
}
@@ -1177,12 +1056,11 @@ 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"])
- @pytest.mark.skip(
- reason="currently no good way to test endpoints defining 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(
@@ -1192,7 +1070,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",
@@ -1206,9 +1083,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(
@@ -1218,7 +1093,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",
@@ -1234,9 +1108,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 ''"):
@@ -1247,7 +1119,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",
diff --git a/tests/api_resources/workflows/test_steps.py b/tests/api_resources/workflows/test_steps.py
index aede731..4adb797 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(
@@ -40,15 +36,14 @@ 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",
)
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 +58,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 +75,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 ''"):
@@ -105,11 +96,11 @@ 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"])
-
- @pytest.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 = 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_preview_template(self, async_client: AsyncKnockMgmt) -> None:
step = await async_client.workflows.steps.preview_template(
@@ -120,9 +111,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(
@@ -130,15 +119,14 @@ 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",
)
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(
@@ -153,9 +141,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(
@@ -172,9 +158,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 ''"):
diff --git a/tests/conftest.py b/tests/conftest.py
index c8f563b..6df9560 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,13 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
from __future__ import annotations
import os
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]
@@ -25,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")
@@ -43,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
diff --git a/tests/test_client.py b/tests/test_client.py
index 2e1a8fd..b47066f 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,12 +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 KnockMgmtError, APIResponseValidationError
+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,
)
@@ -49,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(
@@ -131,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(
@@ -171,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():
@@ -187,12 +190,13 @@ 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"
- def test_copy_build_request(self) -> None:
+ @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, 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)
@@ -249,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)
@@ -269,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:
@@ -283,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(
@@ -296,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(
@@ -309,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:
@@ -320,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,
@@ -339,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"))
@@ -374,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",
@@ -386,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",
@@ -397,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",
@@ -408,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",
@@ -419,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",
@@ -430,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",
@@ -444,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",
@@ -458,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",
@@ -474,7 +489,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"]},
@@ -501,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
@@ -510,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):
@@ -526,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
"""
@@ -553,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
@@ -567,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)
@@ -598,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",
@@ -625,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",
@@ -652,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)
@@ -705,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",
[
@@ -732,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)
@@ -821,57 +844,100 @@ 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),
+ )
-class TestAsyncKnockMgmt:
- client = AsyncKnockMgmt(base_url=base_url, service_token=service_token, _strict_response_validation=True)
+ @pytest.mark.respx(base_url=base_url)
+ 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 = 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)
- @pytest.mark.asyncio
- async def test_raw_response(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:
+ 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:
+ @pytest.mark.respx(base_url=base_url)
+ 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,
@@ -907,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,
@@ -947,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():
@@ -963,12 +1032,13 @@ 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"
- def test_copy_build_request(self) -> None:
+ @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, 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)
@@ -1025,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
@@ -1045,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:
@@ -1059,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(
@@ -1072,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(
@@ -1085,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:
@@ -1095,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,
@@ -1115,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"))
@@ -1129,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,
@@ -1150,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",
@@ -1162,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",
@@ -1173,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",
@@ -1184,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",
@@ -1195,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",
@@ -1206,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",
@@ -1220,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",
@@ -1234,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",
@@ -1250,7 +1333,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"]},
@@ -1277,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
@@ -1286,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):
@@ -1302,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
"""
@@ -1329,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
)
@@ -1343,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/"
@@ -1365,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",
@@ -1374,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",
@@ -1392,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",
@@ -1401,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",
@@ -1419,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",
@@ -1428,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)
@@ -1472,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
@@ -1484,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",
[
@@ -1511,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,
@@ -1555,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:
@@ -1581,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:
@@ -1604,47 +1693,55 @@ 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
+ 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, 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 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, 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 async_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"
diff --git a/tests/test_models.py b/tests/test_models.py
index 0bb400d..f9af039 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
@@ -8,8 +8,8 @@
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._models import BaseModel, construct_type
+from knock_mapi._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
+from knock_mapi._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
class BasicModel(BaseModel):
@@ -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:
@@ -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,10 +830,10 @@ 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(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
@@ -889,3 +889,75 @@ 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)
+
+
+@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
+
+ 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"
diff --git a/tests/test_transform.py b/tests/test_transform.py
index 6db6a29..d019655 100644
--- a/tests/test_transform.py
+++ b/tests/test_transform.py
@@ -8,14 +8,14 @@
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,
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"}}
@@ -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) == {}
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/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)
diff --git a/tests/utils.py b/tests/utils.py
index a6099c6..6ec99c8 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,10 +15,11 @@
is_list_type,
is_union_type,
extract_type_arg,
+ is_sequence_type,
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)
@@ -27,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),
@@ -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: