From e8fdf784267f76c99d0c2bccf3a676983a3b8e0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:48:16 +0000 Subject: [PATCH 1/8] Bump the dependencies group with 11 updates Bumps the dependencies group with 11 updates: | Package | From | To | | --- | --- | --- | | [openai](https://github.com/openai/openai-python) | `1.45.1` | `1.47.1` | | cohere | `5.9.2` | `5.9.4` | | [huggingface-hub](https://github.com/huggingface/huggingface_hub) | `0.24.7` | `0.25.1` | | [boto3](https://github.com/boto/boto3) | `1.35.19` | `1.35.24` | | [pymongo](https://github.com/mongodb/mongo-python-driver) | `4.8.0` | `4.9.1` | | [marqo](https://github.com/marqo-ai/marqo) | `3.8.0` | `3.8.1` | | [elevenlabs](https://github.com/elevenlabs/elevenlabs-python) | `1.8.1` | `1.9.0` | | [qdrant-client](https://github.com/qdrant/qdrant-client) | `1.11.1` | `1.11.2` | | [astrapy](https://github.com/datastax/astrapy) | `1.4.2` | `1.5.0` | | [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) | `2.0.34` | `2.0.35` | | [diffusers](https://github.com/huggingface/diffusers) | `0.30.2` | `0.30.3` | Updates `openai` from 1.45.1 to 1.47.1 - [Release notes](https://github.com/openai/openai-python/releases) - [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md) - [Commits](https://github.com/openai/openai-python/compare/v1.45.1...v1.47.1) Updates `cohere` from 5.9.2 to 5.9.4 Updates `huggingface-hub` from 0.24.7 to 0.25.1 - [Release notes](https://github.com/huggingface/huggingface_hub/releases) - [Commits](https://github.com/huggingface/huggingface_hub/compare/v0.24.7...v0.25.1) Updates `boto3` from 1.35.19 to 1.35.24 - [Release notes](https://github.com/boto/boto3/releases) - [Commits](https://github.com/boto/boto3/compare/1.35.19...1.35.24) Updates `pymongo` from 4.8.0 to 4.9.1 - [Release notes](https://github.com/mongodb/mongo-python-driver/releases) - [Changelog](https://github.com/mongodb/mongo-python-driver/blob/master/doc/changelog.rst) - [Commits](https://github.com/mongodb/mongo-python-driver/compare/4.8.0...4.9.1) Updates `marqo` from 3.8.0 to 3.8.1 - [Release notes](https://github.com/marqo-ai/marqo/releases) - [Changelog](https://github.com/marqo-ai/marqo/blob/mainline/RELEASE.md) - [Commits](https://github.com/marqo-ai/marqo/commits) Updates `elevenlabs` from 1.8.1 to 1.9.0 - [Release notes](https://github.com/elevenlabs/elevenlabs-python/releases) - [Commits](https://github.com/elevenlabs/elevenlabs-python/compare/v1.8.1...1.9.0) Updates `qdrant-client` from 1.11.1 to 1.11.2 - [Release notes](https://github.com/qdrant/qdrant-client/releases) - [Commits](https://github.com/qdrant/qdrant-client/compare/v1.11.1...v1.11.2) Updates `astrapy` from 1.4.2 to 1.5.0 - [Release notes](https://github.com/datastax/astrapy/releases) - [Changelog](https://github.com/datastax/astrapy/blob/master/CHANGES) - [Commits](https://github.com/datastax/astrapy/compare/v1.4.2...v1.5.0) Updates `sqlalchemy` from 2.0.34 to 2.0.35 - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) Updates `diffusers` from 0.30.2 to 0.30.3 - [Release notes](https://github.com/huggingface/diffusers/releases) - [Commits](https://github.com/huggingface/diffusers/compare/v0.30.2...v0.30.3) --- updated-dependencies: - dependency-name: openai dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: cohere dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: huggingface-hub dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: pymongo dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: marqo dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: elevenlabs dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: qdrant-client dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: astrapy dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies - dependency-name: sqlalchemy dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies - dependency-name: diffusers dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dependencies ... Signed-off-by: dependabot[bot] --- poetry.lock | 281 +++++++++++++++++++++++++------------------------ pyproject.toml | 2 +- 2 files changed, 146 insertions(+), 137 deletions(-) diff --git a/poetry.lock b/poetry.lock index 08508f7622..a053df3e0a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -250,13 +250,13 @@ files = [ [[package]] name = "astrapy" -version = "1.4.2" +version = "1.5.0" description = "AstraPy is a Pythonic SDK for DataStax Astra and its Data API" optional = true python-versions = "<4.0.0,>=3.8.0" files = [ - {file = "astrapy-1.4.2-py3-none-any.whl", hash = "sha256:e8b595377c6448ae675823b614b24520fbdb35572c260b6ed23383da6391478e"}, - {file = "astrapy-1.4.2.tar.gz", hash = "sha256:8fd3d2acaf439c5069d74e3d76e8a3e976120896d87cc2b05a6af51d528c6094"}, + {file = "astrapy-1.5.0-py3-none-any.whl", hash = "sha256:eb805202c976f5c3f5a6dcc2bd79f4c566e68b2c0ee25bfa3f56bf9db7b454b1"}, + {file = "astrapy-1.5.0.tar.gz", hash = "sha256:a9d75fade84f67f6fdf8d1286ed0bfb265f44c109f4f26acf50ed4883abef035"}, ] [package.dependencies] @@ -349,17 +349,17 @@ lxml = ["lxml"] [[package]] name = "boto3" -version = "1.35.19" +version = "1.35.24" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.19-py3-none-any.whl", hash = "sha256:84b3fe1727945bc3cada832d969ddb3dc0d08fce1677064ca8bdc13a89c1a143"}, - {file = "boto3-1.35.19.tar.gz", hash = "sha256:9979fe674780a0b7100eae9156d74ee374cd1638a9f61c77277e3ce712f3e496"}, + {file = "boto3-1.35.24-py3-none-any.whl", hash = "sha256:97fcc1a14cbc759e4ba9535ced703a99fcf652c9c4b8dfcd06f292c80551684b"}, + {file = "boto3-1.35.24.tar.gz", hash = "sha256:be7807f30f26d6c0057e45cfd09dad5968e664488bf4f9138d0bb7a0f6d8ed40"}, ] [package.dependencies] -botocore = ">=1.35.19,<1.36.0" +botocore = ">=1.35.24,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -780,13 +780,13 @@ xray = ["mypy-boto3-xray (>=1.35.0,<1.36.0)"] [[package]] name = "botocore" -version = "1.35.19" +version = "1.35.24" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.19-py3-none-any.whl", hash = "sha256:c83f7f0cacfe7c19b109b363ebfa8736e570d24922f16ed371681f58ebab44a9"}, - {file = "botocore-1.35.19.tar.gz", hash = "sha256:42d6d8db7250cbd7899f786f9861e02cab17dc238f64d6acb976098ed9809625"}, + {file = "botocore-1.35.24-py3-none-any.whl", hash = "sha256:eb9ccc068255cc3d24c36693fda6aec7786db05ae6c2b13bcba66dce6a13e2e3"}, + {file = "botocore-1.35.24.tar.gz", hash = "sha256:1e59b0f14f4890c4f70bd6a58a634b9464bed1c4c6171f87c8795d974ade614b"}, ] [package.dependencies] @@ -1107,13 +1107,13 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "cohere" -version = "5.9.2" +version = "5.9.4" description = "" optional = true python-versions = "<4.0,>=3.8" files = [ - {file = "cohere-5.9.2-py3-none-any.whl", hash = "sha256:169ee06b0a54f8a913d42b19123bd72c1a72833275d544a52606d307f5547a7b"}, - {file = "cohere-5.9.2.tar.gz", hash = "sha256:1860c527b2a8a5593873a342b0bf572220b6db7966c0782076b3f2740ab3d94d"}, + {file = "cohere-5.9.4-py3-none-any.whl", hash = "sha256:d1b31d8ba32e338b3aa91737aa98dc74de8778ed8e397ab799739b5f060f44e7"}, + {file = "cohere-5.9.4.tar.gz", hash = "sha256:ed0fa256c51423175c208650dffcb534ae112dc3ab7703de352e2adaf99dd50b"}, ] [package.dependencies] @@ -1350,13 +1350,13 @@ packaging = "*" [[package]] name = "diffusers" -version = "0.30.2" +version = "0.30.3" description = "State-of-the-art diffusion in PyTorch and JAX." optional = true python-versions = ">=3.8.0" files = [ - {file = "diffusers-0.30.2-py3-none-any.whl", hash = "sha256:739826043147c2b59560944591dfdea5d24cd4fb15e751abbe20679a289bece8"}, - {file = "diffusers-0.30.2.tar.gz", hash = "sha256:641875f78f36bdfa4b9af752b124d1fd6d431eadd5547fe0a3f354ae0af2636c"}, + {file = "diffusers-0.30.3-py3-none-any.whl", hash = "sha256:1b70209e4d2c61223b96a7e13bc4d70869c8b0b68f54a35ce3a67fcf813edeee"}, + {file = "diffusers-0.30.3.tar.gz", hash = "sha256:67c5eb25d5b50bf0742624ef43fe0f6d1e1604f64aad3e8558469cbe89ecf72f"}, ] [package.dependencies] @@ -1474,13 +1474,13 @@ lxml = ["lxml (>=5.2.2)"] [[package]] name = "elevenlabs" -version = "1.8.1" +version = "1.9.0" description = "" optional = true python-versions = "<4.0,>=3.8" files = [ - {file = "elevenlabs-1.8.1-py3-none-any.whl", hash = "sha256:d9a2a62963b008f4b8f52326984b1cf35fd455ebbe24ff136cb3009908e1185d"}, - {file = "elevenlabs-1.8.1.tar.gz", hash = "sha256:a6309fc7ca91d379dfbec3fddeb5a6b755847c25fa935f936654d55a95d7b9a9"}, + {file = "elevenlabs-1.9.0-py3-none-any.whl", hash = "sha256:e8828d154085c717bc5b35c5d8a65d3421655a7670643fc596ba54dc53e17c30"}, + {file = "elevenlabs-1.9.0.tar.gz", hash = "sha256:873baad8f687b865436f2ca6d697a0d75f38796bec1cc0728c9ed589d1d846b2"}, ] [package.dependencies] @@ -2270,13 +2270,13 @@ files = [ [[package]] name = "huggingface-hub" -version = "0.24.7" +version = "0.25.1" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = true python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.24.7-py3-none-any.whl", hash = "sha256:a212c555324c8a7b1ffdd07266bb7e7d69ca71aa238d27b7842d65e9a26ac3e5"}, - {file = "huggingface_hub-0.24.7.tar.gz", hash = "sha256:0ad8fb756e2831da0ac0491175b960f341fe06ebcf80ed6f8728313f95fc0207"}, + {file = "huggingface_hub-0.25.1-py3-none-any.whl", hash = "sha256:a5158ded931b3188f54ea9028097312cb0acd50bffaaa2612014c3c526b44972"}, + {file = "huggingface_hub-0.25.1.tar.gz", hash = "sha256:9ff7cb327343211fbd06e2b149b8f362fd1e389454f3f14c6db75a4999ee20ff"}, ] [package.dependencies] @@ -2905,13 +2905,13 @@ files = [ [[package]] name = "marqo" -version = "3.8.0" +version = "3.8.1" description = "Tensor search for humans" optional = true python-versions = ">=3" files = [ - {file = "marqo-3.8.0-py3-none-any.whl", hash = "sha256:6b3ac5d5b308aa771798c3bbf95ad42dc6bb73e34701ba9073f9c4eaf4a5ac8a"}, - {file = "marqo-3.8.0.tar.gz", hash = "sha256:89f36227c54ad0e60a638c524e9864211a3aa7898bec3d6bc2473a748fe7c8b3"}, + {file = "marqo-3.8.1-py3-none-any.whl", hash = "sha256:ff88782766bfaccd371ae595832e024a90a438406436415251ecf75949e22088"}, + {file = "marqo-3.8.1.tar.gz", hash = "sha256:1e7565805bc78752bd18f1fcaa21fa008b63422ca354cbdc26a7ada1fe9ac9b8"}, ] [package.dependencies] @@ -3716,13 +3716,13 @@ httpx = ">=0.27.0,<0.28.0" [[package]] name = "openai" -version = "1.45.1" +version = "1.47.1" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.45.1-py3-none-any.whl", hash = "sha256:4a6cce402aec803ae57ae7eff4b5b94bf6c0e1703a8d85541c27243c2adeadf8"}, - {file = "openai-1.45.1.tar.gz", hash = "sha256:f79e384916b219ab2f028bbf9c778e81291c61eb0645ccfa1828a4b18b55d534"}, + {file = "openai-1.47.1-py3-none-any.whl", hash = "sha256:34277583bf268bb2494bc03f48ac123788c5e2a914db1d5a23d5edc29d35c825"}, + {file = "openai-1.47.1.tar.gz", hash = "sha256:62c8f5f478f82ffafc93b33040f8bb16a45948306198bd0cba2da2ecd9cf7323"}, ] [package.dependencies] @@ -4663,61 +4663,70 @@ extra = ["pygments (>=2.12)"] [[package]] name = "pymongo" -version = "4.8.0" +version = "4.9.1" description = "Python driver for MongoDB " optional = true python-versions = ">=3.8" files = [ - {file = "pymongo-4.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2b7bec27e047e84947fbd41c782f07c54c30c76d14f3b8bf0c89f7413fac67a"}, - {file = "pymongo-4.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c68fe128a171493018ca5c8020fc08675be130d012b7ab3efe9e22698c612a1"}, - {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920d4f8f157a71b3cb3f39bc09ce070693d6e9648fb0e30d00e2657d1dca4e49"}, - {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52b4108ac9469febba18cea50db972605cc43978bedaa9fea413378877560ef8"}, - {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:180d5eb1dc28b62853e2f88017775c4500b07548ed28c0bd9c005c3d7bc52526"}, - {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aec2b9088cdbceb87e6ca9c639d0ff9b9d083594dda5ca5d3c4f6774f4c81b33"}, - {file = "pymongo-4.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0cf61450feadca81deb1a1489cb1a3ae1e4266efd51adafecec0e503a8dcd84"}, - {file = "pymongo-4.8.0-cp310-cp310-win32.whl", hash = "sha256:8b18c8324809539c79bd6544d00e0607e98ff833ca21953df001510ca25915d1"}, - {file = "pymongo-4.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e5df28f74002e37bcbdfdc5109799f670e4dfef0fb527c391ff84f078050e7b5"}, - {file = "pymongo-4.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6b50040d9767197b77ed420ada29b3bf18a638f9552d80f2da817b7c4a4c9c68"}, - {file = "pymongo-4.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:417369ce39af2b7c2a9c7152c1ed2393edfd1cbaf2a356ba31eb8bcbd5c98dd7"}, - {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf821bd3befb993a6db17229a2c60c1550e957de02a6ff4dd0af9476637b2e4d"}, - {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9365166aa801c63dff1a3cb96e650be270da06e3464ab106727223123405510f"}, - {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc8b8582f4209c2459b04b049ac03c72c618e011d3caa5391ff86d1bda0cc486"}, - {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e5019f75f6827bb5354b6fef8dfc9d6c7446894a27346e03134d290eb9e758"}, - {file = "pymongo-4.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b5802151fc2b51cd45492c80ed22b441d20090fb76d1fd53cd7760b340ff554"}, - {file = "pymongo-4.8.0-cp311-cp311-win32.whl", hash = "sha256:4bf58e6825b93da63e499d1a58de7de563c31e575908d4e24876234ccb910eba"}, - {file = "pymongo-4.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:b747c0e257b9d3e6495a018309b9e0c93b7f0d65271d1d62e572747f4ffafc88"}, - {file = "pymongo-4.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e6a720a3d22b54183352dc65f08cd1547204d263e0651b213a0a2e577e838526"}, - {file = "pymongo-4.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31e4d21201bdf15064cf47ce7b74722d3e1aea2597c6785882244a3bb58c7eab"}, - {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6b804bb4f2d9dc389cc9e827d579fa327272cdb0629a99bfe5b83cb3e269ebf"}, - {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f2fbdb87fe5075c8beb17a5c16348a1ea3c8b282a5cb72d173330be2fecf22f5"}, - {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd39455b7ee70aabee46f7399b32ab38b86b236c069ae559e22be6b46b2bbfc4"}, - {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:940d456774b17814bac5ea7fc28188c7a1338d4a233efbb6ba01de957bded2e8"}, - {file = "pymongo-4.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:236bbd7d0aef62e64caf4b24ca200f8c8670d1a6f5ea828c39eccdae423bc2b2"}, - {file = "pymongo-4.8.0-cp312-cp312-win32.whl", hash = "sha256:47ec8c3f0a7b2212dbc9be08d3bf17bc89abd211901093e3ef3f2adea7de7a69"}, - {file = "pymongo-4.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e84bc7707492f06fbc37a9f215374d2977d21b72e10a67f1b31893ec5a140ad8"}, - {file = "pymongo-4.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:519d1bab2b5e5218c64340b57d555d89c3f6c9d717cecbf826fb9d42415e7750"}, - {file = "pymongo-4.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:87075a1feb1e602e539bdb1ef8f4324a3427eb0d64208c3182e677d2c0718b6f"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f53429515d2b3e86dcc83dadecf7ff881e538c168d575f3688698a8707b80a"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fdc20cd1e1141b04696ffcdb7c71e8a4a665db31fe72e51ec706b3bdd2d09f36"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:284d0717d1a7707744018b0b6ee7801b1b1ff044c42f7be7a01bb013de639470"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5bf0eb8b6ef40fa22479f09375468c33bebb7fe49d14d9c96c8fd50355188b0"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ecd71b9226bd1d49416dc9f999772038e56f415a713be51bf18d8676a0841c8"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0061af6e8c5e68b13f1ec9ad5251247726653c5af3c0bbdfbca6cf931e99216"}, - {file = "pymongo-4.8.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:658d0170f27984e0d89c09fe5c42296613b711a3ffd847eb373b0dbb5b648d5f"}, - {file = "pymongo-4.8.0-cp38-cp38-win32.whl", hash = "sha256:3ed1c316718a2836f7efc3d75b4b0ffdd47894090bc697de8385acd13c513a70"}, - {file = "pymongo-4.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:7148419eedfea9ecb940961cfe465efaba90595568a1fb97585fb535ea63fe2b"}, - {file = "pymongo-4.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8400587d594761e5136a3423111f499574be5fd53cf0aefa0d0f05b180710b0"}, - {file = "pymongo-4.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af3e98dd9702b73e4e6fd780f6925352237f5dce8d99405ff1543f3771201704"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de3a860f037bb51f968de320baef85090ff0bbb42ec4f28ec6a5ddf88be61871"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fc18b3a093f3db008c5fea0e980dbd3b743449eee29b5718bc2dc15ab5088bb"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18c9d8f975dd7194c37193583fd7d1eb9aea0c21ee58955ecf35362239ff31ac"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:408b2f8fdbeca3c19e4156f28fff1ab11c3efb0407b60687162d49f68075e63c"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6564780cafd6abeea49759fe661792bd5a67e4f51bca62b88faab497ab5fe89"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d18d86bc9e103f4d3d4f18b85a0471c0e13ce5b79194e4a0389a224bb70edd53"}, - {file = "pymongo-4.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9097c331577cecf8034422956daaba7ec74c26f7b255d718c584faddd7fa2e3c"}, - {file = "pymongo-4.8.0-cp39-cp39-win32.whl", hash = "sha256:d5428dbcd43d02f6306e1c3c95f692f68b284e6ee5390292242f509004c9e3a8"}, - {file = "pymongo-4.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:ef7225755ed27bfdb18730c68f6cb023d06c28f2b734597480fb4c0e500feb6f"}, - {file = "pymongo-4.8.0.tar.gz", hash = "sha256:454f2295875744dc70f1881e4b2eb99cdad008a33574bc8aaf120530f66c0cde"}, + {file = "pymongo-4.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc3d070d746ab79e9b393a5c236df20e56607389af2b79bf1bfe9a841117558e"}, + {file = "pymongo-4.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fe709d05654c12fc513617c8d5c8d05b7e9cf1d5d94ada68add4e89530c867d2"}, + {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa4493f304b33c5d2ecee3055c98889ac6724d56f5f922d47420a45d0d4099c9"}, + {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8e8b8deba6a4bff3dd5421071083219521c74d2acae0322de5c06f1a66c56af"}, + {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3645aff8419ca60f9ccd08966b2f6b0d78053f9f98a814d025426f1d874c19a"}, + {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51dbc6251c6783dfcc7d657c346986d8bad7210989b2fe15de16db5204a8e7ae"}, + {file = "pymongo-4.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d7aa9cc2d92e73bdb036c578ba019da94ea165eb147e691cd910a6fab7ce3b7"}, + {file = "pymongo-4.9.1-cp310-cp310-win32.whl", hash = "sha256:8b632e01617f2608880f7b9926f54a5f5ebb51631996e0540fff7fc7980663c9"}, + {file = "pymongo-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:f05e34d401be871d7c87cb10727d49315444e4ded07ff876a595e4c23b7436da"}, + {file = "pymongo-4.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bb3d5282278594753089dc7da48bfae4a7f337a2dd4d397eabb591c649e58d0"}, + {file = "pymongo-4.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f0d5258bc85a4e6b5bcae8160628168e71ec4625a58ceb53327c3280a0b6914"}, + {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96462fb2175f740701d229f52018ea6e4adc4148c4112e6628bb359dd534a3df"}, + {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:286fb275267f0293364ba579f6354452599161f1902ad411061c7f744ab88328"}, + {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cddb51cead9700c4dccc916952bc0321b8d766bf782d374bfa0e93ef47c1d20"}, + {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d79f20f9c7cbc1c708fb80b648b6fbd3220fd3437a9bd6017c1eb592e03b361"}, + {file = "pymongo-4.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd3352eaf578f8e9bdea7a5692910eedad1e8680f60726fc70e99c8af51a5449"}, + {file = "pymongo-4.9.1-cp311-cp311-win32.whl", hash = "sha256:ea3f0196e7c311b9944a609ac175bd91ab97952164a1246716fdd38d53ca3bcc"}, + {file = "pymongo-4.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4c793db8457c856f333f396798470b9bfe405e17c307d581532c74cec70150c"}, + {file = "pymongo-4.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:47b4896544095d172c366dd4d4ea1da6b0ab1a77d8416897cc1801e2421b1e67"}, + {file = "pymongo-4.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fbb1c7dfcf6c44e9e1928290631c7603817991cdf570691c9e15fca594918435"}, + {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7689da1d1b444284e4ea9ab2eb64a15307b6b795918c0f3cd7774dd1d8a7556"}, + {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f962d74201c772555f7a78792fed820a5ea76db5c7ee6cf43748e411b44e430"}, + {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08fbab69f3fb6f8088c81f4c4a8abd84a99c132034f5e27e47f894bbcb6bf439"}, + {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4327c0d9bd616b8289691360f2d4a09a72fe35479795832eae0d4ff78af53923"}, + {file = "pymongo-4.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34e4993ae78be56f9e27a141168a1ab78253576fa3e893fa335a719ce204c3ef"}, + {file = "pymongo-4.9.1-cp312-cp312-win32.whl", hash = "sha256:e1f346811d4a2369f88ab7a6f886fa9c3bbc9ed4e4f4a3becca8717a73d465cb"}, + {file = "pymongo-4.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:a2b12c74cfd90147babb77f9728646bcedfdbd2bd2a5b4130a00e3a0af1a3d34"}, + {file = "pymongo-4.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a40ea8bc9cffb61c5c9c426c430d22235e085e610ee81ae075ddf51f12f76236"}, + {file = "pymongo-4.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75d5974f874acdb2f125bdbe785045b23a39ecce1d3143dd5712800c7b6d25eb"}, + {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f23a046531030318622414f21198e232cf93c5640da9a80b45596a059c8cc090"}, + {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91b1a92214c3912af5467f77c2f6435cd76f6de64c70cba7bb4ee43eba7f459e"}, + {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a846423c4535428f69a90a1451df3718bc59f0c4ab685b9e96d3071951e0be4"}, + {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d476d91a5c9e6c37bc8ec3fb294e1c01d95736ccf01a59bb1540fe2f710f826e"}, + {file = "pymongo-4.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:172d8ba0f567e351a18765db23dab7dbcfdffd91a8788d90d46b350f80a40781"}, + {file = "pymongo-4.9.1-cp313-cp313-win32.whl", hash = "sha256:95418e334629440f70fe5ceeefc6cbbd50defb566901c8d68179ffbaec8d5f01"}, + {file = "pymongo-4.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:1dfd2aa30174d36a3ef1dae4ee4c89710c2d65cac52ce6e13f17c710edbd61cf"}, + {file = "pymongo-4.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c4204fad54830a3173a5c939cd052d0561fba03dba7e0ff6852fd631f3314aa4"}, + {file = "pymongo-4.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:375765ec81b1f0a26d08928afea0c3dff897c36080a090be53fc7b70cc51d497"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d1b959a3dda0775d9111622ee47ad47772aed3a9da2e7d5f2f513fa68175dea"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42c19d2b094cdd0ead7dbb38860bbe8268c140334ce55d8b39204ddb4ebd4904"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fac1def9e9073f1c80198c99f0ec39c2528236c8912d96d7fd3b0237f4c523a"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b347052d510989d1f52b8553b31297f21cf74bd9f6aed71ee84e563492f4ff17"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b4b961fce213f2bcdc92268f85111a3668c61b9b4d4e7ece27dce3a137cfcbd"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a0b10cf51ec14a487c94709d294c00e1fb6a0a4c38cdc3acfb2ced5ef60972a0"}, + {file = "pymongo-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:679b8d55854da7c7fdb82aa5e092ab4de0144daf6758defed8ab00ff9ce05360"}, + {file = "pymongo-4.9.1-cp38-cp38-win32.whl", hash = "sha256:432ad395d2233056b042ccc73234e7136aa65d944d6bd8b5138394bd38aaff79"}, + {file = "pymongo-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:9fbe9fad27619ac4cfda5df0ade26a99906da7dfe7b01deddc25997eb1804e4c"}, + {file = "pymongo-4.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:99b611ff75b5d9e17183dcf9584a7b04f9db07e51a162f23ea05e485e0735c0a"}, + {file = "pymongo-4.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8089003a99127f917bdbeec177d41cef019cda8ec70534c1018cb60aacd23c2a"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d78adf25967c06298c7e488f4cfab79a390fc32c2b1d428613976f99031603d"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56877cfcdf7dfc5c6408e4551ec0d6d65ebbca4d744a0bc90400f09ef6bbcc8a"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d2efe559d0d96bc0b74b3ff76701ad6f6e1a65f6581b573dcacc29158131c8"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f838f613e74b4dad8ace0d90f42346005bece4eda5bf6d389cfadb8322d39316"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db5b299e11284f8d82ce2983d8e19fcc28f98f902a179709ef1982b4cca6f8b8"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b23211c031b45d0f32de83ab7d77f9c26f1025c2d2c91463a5d8594a16103655"}, + {file = "pymongo-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:687cf70e096381bc65b4273a6a9319617618f7ace65caffc356e1099c4a68511"}, + {file = "pymongo-4.9.1-cp39-cp39-win32.whl", hash = "sha256:e02b03e3815b80a63e773e4c32aed3cf5633d406f376477be74550295c211256"}, + {file = "pymongo-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:0492ef43f3342354cf581712e431621c221f60c877ebded84e3f3e53b71bbbe0"}, + {file = "pymongo-4.9.1.tar.gz", hash = "sha256:b7f2d34390acf60e229c30037d1473fcf69f4536cd7f48f6f78c0c931c61c505"}, ] [package.dependencies] @@ -4725,12 +4734,12 @@ dnspython = ">=1.16.0,<3.0.0" [package.extras] aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] -docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] -encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.6.0,<2.0.0)"] +docs = ["furo (==2023.9.10)", "readthedocs-sphinx-search (>=0.3,<1.0)", "sphinx (>=5.3,<8)", "sphinx-autobuild (>=2020.9.1)", "sphinx-rtd-theme (>=2,<3)", "sphinxcontrib-shellcheck (>=1,<2)"] +encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.10.0,<2.0.0)"] gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] -test = ["pytest (>=7)"] +test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"] zstd = ["zstandard"] [[package]] @@ -5077,13 +5086,13 @@ pyyaml = "*" [[package]] name = "qdrant-client" -version = "1.11.1" +version = "1.11.2" description = "Client library for the Qdrant vector search engine" optional = true python-versions = ">=3.8" files = [ - {file = "qdrant_client-1.11.1-py3-none-any.whl", hash = "sha256:1375fad77c825c957181ff53775fb900c4383e817f864ea30b2605314da92f07"}, - {file = "qdrant_client-1.11.1.tar.gz", hash = "sha256:bfc23239b027073352ad92152209ec50281519686b7da3041612faece0fcdfbd"}, + {file = "qdrant_client-1.11.2-py3-none-any.whl", hash = "sha256:3151e3da61588ad138dfcd6760c2f13e57251c8b0c62001bfd0e03bb7bcd6c8e"}, + {file = "qdrant_client-1.11.2.tar.gz", hash = "sha256:0d5aa3f778077762963a754459c9c7144ba48e13dea62e559323924126a1b4a4"}, ] [package.dependencies] @@ -5860,60 +5869,60 @@ files = [ [[package]] name = "sqlalchemy" -version = "2.0.34" +version = "2.0.35" description = "Database Abstraction Library" optional = true python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.34-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:95d0b2cf8791ab5fb9e3aa3d9a79a0d5d51f55b6357eecf532a120ba3b5524db"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:243f92596f4fd4c8bd30ab8e8dd5965afe226363d75cab2468f2c707f64cd83b"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ea54f7300553af0a2a7235e9b85f4204e1fc21848f917a3213b0e0818de9a24"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:173f5f122d2e1bff8fbd9f7811b7942bead1f5e9f371cdf9e670b327e6703ebd"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:196958cde924a00488e3e83ff917be3b73cd4ed8352bbc0f2989333176d1c54d"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd90c221ed4e60ac9d476db967f436cfcecbd4ef744537c0f2d5291439848768"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-win32.whl", hash = "sha256:3166dfff2d16fe9be3241ee60ece6fcb01cf8e74dd7c5e0b64f8e19fab44911b"}, - {file = "SQLAlchemy-2.0.34-cp310-cp310-win_amd64.whl", hash = "sha256:6831a78bbd3c40f909b3e5233f87341f12d0b34a58f14115c9e94b4cdaf726d3"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7db3db284a0edaebe87f8f6642c2b2c27ed85c3e70064b84d1c9e4ec06d5d84"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:430093fce0efc7941d911d34f75a70084f12f6ca5c15d19595c18753edb7c33b"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79cb400c360c7c210097b147c16a9e4c14688a6402445ac848f296ade6283bbc"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1b30f31a36c7f3fee848391ff77eebdd3af5750bf95fbf9b8b5323edfdb4ec"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fddde2368e777ea2a4891a3fb4341e910a056be0bb15303bf1b92f073b80c02"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:80bd73ea335203b125cf1d8e50fef06be709619eb6ab9e7b891ea34b5baa2287"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-win32.whl", hash = "sha256:6daeb8382d0df526372abd9cb795c992e18eed25ef2c43afe518c73f8cccb721"}, - {file = "SQLAlchemy-2.0.34-cp311-cp311-win_amd64.whl", hash = "sha256:5bc08e75ed11693ecb648b7a0a4ed80da6d10845e44be0c98c03f2f880b68ff4"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:53e68b091492c8ed2bd0141e00ad3089bcc6bf0e6ec4142ad6505b4afe64163e"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bcd18441a49499bf5528deaa9dee1f5c01ca491fc2791b13604e8f972877f812"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:165bbe0b376541092bf49542bd9827b048357f4623486096fc9aaa6d4e7c59a2"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3330415cd387d2b88600e8e26b510d0370db9b7eaf984354a43e19c40df2e2b"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97b850f73f8abbffb66ccbab6e55a195a0eb655e5dc74624d15cff4bfb35bd74"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee4c6917857fd6121ed84f56d1dc78eb1d0e87f845ab5a568aba73e78adf83"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-win32.whl", hash = "sha256:fbb034f565ecbe6c530dff948239377ba859420d146d5f62f0271407ffb8c580"}, - {file = "SQLAlchemy-2.0.34-cp312-cp312-win_amd64.whl", hash = "sha256:707c8f44931a4facd4149b52b75b80544a8d824162602b8cd2fe788207307f9a"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:24af3dc43568f3780b7e1e57c49b41d98b2d940c1fd2e62d65d3928b6f95f021"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60ed6ef0a35c6b76b7640fe452d0e47acc832ccbb8475de549a5cc5f90c2c06"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:413c85cd0177c23e32dee6898c67a5f49296640041d98fddb2c40888fe4daa2e"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:25691f4adfb9d5e796fd48bf1432272f95f4bbe5f89c475a788f31232ea6afba"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:526ce723265643dbc4c7efb54f56648cc30e7abe20f387d763364b3ce7506c82"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-win32.whl", hash = "sha256:13be2cc683b76977a700948411a94c67ad8faf542fa7da2a4b167f2244781cf3"}, - {file = "SQLAlchemy-2.0.34-cp37-cp37m-win_amd64.whl", hash = "sha256:e54ef33ea80d464c3dcfe881eb00ad5921b60f8115ea1a30d781653edc2fd6a2"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43f28005141165edd11fbbf1541c920bd29e167b8bbc1fb410d4fe2269c1667a"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b68094b165a9e930aedef90725a8fcfafe9ef95370cbb54abc0464062dbf808f"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1e03db964e9d32f112bae36f0cc1dcd1988d096cfd75d6a588a3c3def9ab2b"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:203d46bddeaa7982f9c3cc693e5bc93db476ab5de9d4b4640d5c99ff219bee8c"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ae92bebca3b1e6bd203494e5ef919a60fb6dfe4d9a47ed2453211d3bd451b9f5"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9661268415f450c95f72f0ac1217cc6f10256f860eed85c2ae32e75b60278ad8"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-win32.whl", hash = "sha256:895184dfef8708e15f7516bd930bda7e50ead069280d2ce09ba11781b630a434"}, - {file = "SQLAlchemy-2.0.34-cp38-cp38-win_amd64.whl", hash = "sha256:6e7cde3a2221aa89247944cafb1b26616380e30c63e37ed19ff0bba5e968688d"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dbcdf987f3aceef9763b6d7b1fd3e4ee210ddd26cac421d78b3c206d07b2700b"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ce119fc4ce0d64124d37f66a6f2a584fddc3c5001755f8a49f1ca0a177ef9796"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a17d8fac6df9835d8e2b4c5523666e7051d0897a93756518a1fe101c7f47f2f0"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ebc11c54c6ecdd07bb4efbfa1554538982f5432dfb8456958b6d46b9f834bb7"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e6965346fc1491a566e019a4a1d3dfc081ce7ac1a736536367ca305da6472a8"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:220574e78ad986aea8e81ac68821e47ea9202b7e44f251b7ed8c66d9ae3f4278"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-win32.whl", hash = "sha256:b75b00083e7fe6621ce13cfce9d4469c4774e55e8e9d38c305b37f13cf1e874c"}, - {file = "SQLAlchemy-2.0.34-cp39-cp39-win_amd64.whl", hash = "sha256:c29d03e0adf3cc1a8c3ec62d176824972ae29b67a66cbb18daff3062acc6faa8"}, - {file = "SQLAlchemy-2.0.34-py3-none-any.whl", hash = "sha256:7286c353ee6475613d8beff83167374006c6b3e3f0e6491bfe8ca610eb1dec0f"}, - {file = "sqlalchemy-2.0.34.tar.gz", hash = "sha256:10d8f36990dd929690666679b0f42235c159a7051534adb135728ee52828dd22"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-win32.whl", hash = "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b"}, + {file = "SQLAlchemy-2.0.35-cp310-cp310-win_amd64.whl", hash = "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-win32.whl", hash = "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e"}, + {file = "SQLAlchemy-2.0.35-cp311-cp311-win_amd64.whl", hash = "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-win32.whl", hash = "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf"}, + {file = "SQLAlchemy-2.0.35-cp312-cp312-win_amd64.whl", hash = "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-win32.whl", hash = "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87"}, + {file = "SQLAlchemy-2.0.35-cp37-cp37m-win_amd64.whl", hash = "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-win32.whl", hash = "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0"}, + {file = "SQLAlchemy-2.0.35-cp38-cp38-win_amd64.whl", hash = "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-win32.whl", hash = "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3"}, + {file = "SQLAlchemy-2.0.35-cp39-cp39-win_amd64.whl", hash = "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f"}, + {file = "SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1"}, + {file = "sqlalchemy-2.0.35.tar.gz", hash = "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f"}, ] [package.dependencies] @@ -7013,4 +7022,4 @@ loaders-sql = ["sqlalchemy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "73313f20ff340b64fb247bba78104a80e20d59d8079861b67131f2d1bc1fe972" +content-hash = "bb4af9c531d0029cb1baeca3a2e94566aaf6d7cb701a6dc07f5e9983bffd1285" diff --git a/pyproject.toml b/pyproject.toml index f8a3899180..591ebc3cde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ requests = "^2.32.0" cohere = { version = "^5.5.4", optional = true } anthropic = { version = ">=0.29,<0.35", optional = true } transformers = { version = "^4.41.1", optional = true, extras=["torch"] } -huggingface-hub = { version = "^0.24.0", optional = true } +huggingface-hub = { version = ">=0.24,<0.26", optional = true } boto3 = { version = "^1.34.119", optional = true } snowflake-sqlalchemy = { version = "^1.6.1", optional = true } pinecone-client = { version = "^3", optional = true } From 3a437075aebf2d5f35964096588b8a856cd5bfab Mon Sep 17 00:00:00 2001 From: Collin Dutter Date: Mon, 23 Sep 2024 11:33:32 -0700 Subject: [PATCH 2/8] Only allow updates from groups (#1197) --- .github/dependabot.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 714fa9ae3b..dd25300fa0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,9 @@ updates: update-types: - "minor" - "patch" + allow: + - dependency-type: production + - dependency-type: development - package-ecosystem: "github-actions" directory: "/" schedule: From 5a1edbdd3c963e097f064b59c9a964b17ceb9d04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:17:51 -0700 Subject: [PATCH 3/8] Bump the group-dependencies group with 7 updates (#1193) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Collin Dutter --- poetry.lock | 102 ++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/poetry.lock b/poetry.lock index a053df3e0a..68d13fd05f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -368,13 +368,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "boto3-stubs" -version = "1.35.19" -description = "Type annotations for boto3 1.35.19 generated with mypy-boto3-builder 8.0.1" +version = "1.35.24" +description = "Type annotations for boto3 1.35.24 generated with mypy-boto3-builder 8.1.1" optional = false python-versions = ">=3.8" files = [ - {file = "boto3_stubs-1.35.19-py3-none-any.whl", hash = "sha256:6adace32995ae7b88675cf0bbde3b4f31876cbf57520db1ec1f392ac32660b4c"}, - {file = "boto3_stubs-1.35.19.tar.gz", hash = "sha256:c5842cd82d4a1570613f178831c2b6d1b60f511b87f56cc014f2a216c03ecf5a"}, + {file = "boto3_stubs-1.35.24-py3-none-any.whl", hash = "sha256:f96c814f26f2ab8fcd42811b7208105f43657fe15ffa82be2cdc7734160e28c4"}, + {file = "boto3_stubs-1.35.24.tar.gz", hash = "sha256:329a9944a75bedd9b343230b03d37c94158e60e7b7a9553e03be9a8f327cd41c"}, ] [package.dependencies] @@ -392,7 +392,7 @@ accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)"] account = ["mypy-boto3-account (>=1.35.0,<1.36.0)"] acm = ["mypy-boto3-acm (>=1.35.0,<1.36.0)"] acm-pca = ["mypy-boto3-acm-pca (>=1.35.0,<1.36.0)"] -all = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)", "mypy-boto3-account (>=1.35.0,<1.36.0)", "mypy-boto3-acm (>=1.35.0,<1.36.0)", "mypy-boto3-acm-pca (>=1.35.0,<1.36.0)", "mypy-boto3-amp (>=1.35.0,<1.36.0)", "mypy-boto3-amplify (>=1.35.0,<1.36.0)", "mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)", "mypy-boto3-amplifyuibuilder (>=1.35.0,<1.36.0)", "mypy-boto3-apigateway (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewaymanagementapi (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewayv2 (>=1.35.0,<1.36.0)", "mypy-boto3-appconfig (>=1.35.0,<1.36.0)", "mypy-boto3-appconfigdata (>=1.35.0,<1.36.0)", "mypy-boto3-appfabric (>=1.35.0,<1.36.0)", "mypy-boto3-appflow (>=1.35.0,<1.36.0)", "mypy-boto3-appintegrations (>=1.35.0,<1.36.0)", "mypy-boto3-application-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-application-insights (>=1.35.0,<1.36.0)", "mypy-boto3-application-signals (>=1.35.0,<1.36.0)", "mypy-boto3-applicationcostprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-appmesh (>=1.35.0,<1.36.0)", "mypy-boto3-apprunner (>=1.35.0,<1.36.0)", "mypy-boto3-appstream (>=1.35.0,<1.36.0)", "mypy-boto3-appsync (>=1.35.0,<1.36.0)", "mypy-boto3-apptest (>=1.35.0,<1.36.0)", "mypy-boto3-arc-zonal-shift (>=1.35.0,<1.36.0)", "mypy-boto3-artifact (>=1.35.0,<1.36.0)", "mypy-boto3-athena (>=1.35.0,<1.36.0)", "mypy-boto3-auditmanager (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)", "mypy-boto3-b2bi (>=1.35.0,<1.36.0)", "mypy-boto3-backup (>=1.35.0,<1.36.0)", "mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)", "mypy-boto3-batch (>=1.35.0,<1.36.0)", "mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-billingconductor (>=1.35.0,<1.36.0)", "mypy-boto3-braket (>=1.35.0,<1.36.0)", "mypy-boto3-budgets (>=1.35.0,<1.36.0)", "mypy-boto3-ce (>=1.35.0,<1.36.0)", "mypy-boto3-chatbot (>=1.35.0,<1.36.0)", "mypy-boto3-chime (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-identity (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-meetings (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-messaging (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-voice (>=1.35.0,<1.36.0)", "mypy-boto3-cleanrooms (>=1.35.0,<1.36.0)", "mypy-boto3-cleanroomsml (>=1.35.0,<1.36.0)", "mypy-boto3-cloud9 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudcontrol (>=1.35.0,<1.36.0)", "mypy-boto3-clouddirectory (>=1.35.0,<1.36.0)", "mypy-boto3-cloudformation (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsm (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsmv2 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearch (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearchdomain (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail-data (>=1.35.0,<1.36.0)", "mypy-boto3-cloudwatch (>=1.35.0,<1.36.0)", "mypy-boto3-codeartifact (>=1.35.0,<1.36.0)", "mypy-boto3-codebuild (>=1.35.0,<1.36.0)", "mypy-boto3-codecatalyst (>=1.35.0,<1.36.0)", "mypy-boto3-codecommit (>=1.35.0,<1.36.0)", "mypy-boto3-codeconnections (>=1.35.0,<1.36.0)", "mypy-boto3-codedeploy (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-reviewer (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-security (>=1.35.0,<1.36.0)", "mypy-boto3-codeguruprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-codepipeline (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-connections (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-identity (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-idp (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-sync (>=1.35.0,<1.36.0)", "mypy-boto3-comprehend (>=1.35.0,<1.36.0)", "mypy-boto3-comprehendmedical (>=1.35.0,<1.36.0)", "mypy-boto3-compute-optimizer (>=1.35.0,<1.36.0)", "mypy-boto3-config (>=1.35.0,<1.36.0)", "mypy-boto3-connect (>=1.35.0,<1.36.0)", "mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)", "mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)", "mypy-boto3-connectcases (>=1.35.0,<1.36.0)", "mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)", "mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)", "mypy-boto3-controltower (>=1.35.0,<1.36.0)", "mypy-boto3-cost-optimization-hub (>=1.35.0,<1.36.0)", "mypy-boto3-cur (>=1.35.0,<1.36.0)", "mypy-boto3-customer-profiles (>=1.35.0,<1.36.0)", "mypy-boto3-databrew (>=1.35.0,<1.36.0)", "mypy-boto3-dataexchange (>=1.35.0,<1.36.0)", "mypy-boto3-datapipeline (>=1.35.0,<1.36.0)", "mypy-boto3-datasync (>=1.35.0,<1.36.0)", "mypy-boto3-datazone (>=1.35.0,<1.36.0)", "mypy-boto3-dax (>=1.35.0,<1.36.0)", "mypy-boto3-deadline (>=1.35.0,<1.36.0)", "mypy-boto3-detective (>=1.35.0,<1.36.0)", "mypy-boto3-devicefarm (>=1.35.0,<1.36.0)", "mypy-boto3-devops-guru (>=1.35.0,<1.36.0)", "mypy-boto3-directconnect (>=1.35.0,<1.36.0)", "mypy-boto3-discovery (>=1.35.0,<1.36.0)", "mypy-boto3-dlm (>=1.35.0,<1.36.0)", "mypy-boto3-dms (>=1.35.0,<1.36.0)", "mypy-boto3-docdb (>=1.35.0,<1.36.0)", "mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)", "mypy-boto3-drs (>=1.35.0,<1.36.0)", "mypy-boto3-ds (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodb (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)", "mypy-boto3-ebs (>=1.35.0,<1.36.0)", "mypy-boto3-ec2 (>=1.35.0,<1.36.0)", "mypy-boto3-ec2-instance-connect (>=1.35.0,<1.36.0)", "mypy-boto3-ecr (>=1.35.0,<1.36.0)", "mypy-boto3-ecr-public (>=1.35.0,<1.36.0)", "mypy-boto3-ecs (>=1.35.0,<1.36.0)", "mypy-boto3-efs (>=1.35.0,<1.36.0)", "mypy-boto3-eks (>=1.35.0,<1.36.0)", "mypy-boto3-eks-auth (>=1.35.0,<1.36.0)", "mypy-boto3-elastic-inference (>=1.35.0,<1.36.0)", "mypy-boto3-elasticache (>=1.35.0,<1.36.0)", "mypy-boto3-elasticbeanstalk (>=1.35.0,<1.36.0)", "mypy-boto3-elastictranscoder (>=1.35.0,<1.36.0)", "mypy-boto3-elb (>=1.35.0,<1.36.0)", "mypy-boto3-elbv2 (>=1.35.0,<1.36.0)", "mypy-boto3-emr (>=1.35.0,<1.36.0)", "mypy-boto3-emr-containers (>=1.35.0,<1.36.0)", "mypy-boto3-emr-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-entityresolution (>=1.35.0,<1.36.0)", "mypy-boto3-es (>=1.35.0,<1.36.0)", "mypy-boto3-events (>=1.35.0,<1.36.0)", "mypy-boto3-evidently (>=1.35.0,<1.36.0)", "mypy-boto3-finspace (>=1.35.0,<1.36.0)", "mypy-boto3-finspace-data (>=1.35.0,<1.36.0)", "mypy-boto3-firehose (>=1.35.0,<1.36.0)", "mypy-boto3-fis (>=1.35.0,<1.36.0)", "mypy-boto3-fms (>=1.35.0,<1.36.0)", "mypy-boto3-forecast (>=1.35.0,<1.36.0)", "mypy-boto3-forecastquery (>=1.35.0,<1.36.0)", "mypy-boto3-frauddetector (>=1.35.0,<1.36.0)", "mypy-boto3-freetier (>=1.35.0,<1.36.0)", "mypy-boto3-fsx (>=1.35.0,<1.36.0)", "mypy-boto3-gamelift (>=1.35.0,<1.36.0)", "mypy-boto3-glacier (>=1.35.0,<1.36.0)", "mypy-boto3-globalaccelerator (>=1.35.0,<1.36.0)", "mypy-boto3-glue (>=1.35.0,<1.36.0)", "mypy-boto3-grafana (>=1.35.0,<1.36.0)", "mypy-boto3-greengrass (>=1.35.0,<1.36.0)", "mypy-boto3-greengrassv2 (>=1.35.0,<1.36.0)", "mypy-boto3-groundstation (>=1.35.0,<1.36.0)", "mypy-boto3-guardduty (>=1.35.0,<1.36.0)", "mypy-boto3-health (>=1.35.0,<1.36.0)", "mypy-boto3-healthlake (>=1.35.0,<1.36.0)", "mypy-boto3-iam (>=1.35.0,<1.36.0)", "mypy-boto3-identitystore (>=1.35.0,<1.36.0)", "mypy-boto3-imagebuilder (>=1.35.0,<1.36.0)", "mypy-boto3-importexport (>=1.35.0,<1.36.0)", "mypy-boto3-inspector (>=1.35.0,<1.36.0)", "mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)", "mypy-boto3-inspector2 (>=1.35.0,<1.36.0)", "mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-iot (>=1.35.0,<1.36.0)", "mypy-boto3-iot-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-devices (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-projects (>=1.35.0,<1.36.0)", "mypy-boto3-iotanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-iotdeviceadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents-data (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleethub (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleetwise (>=1.35.0,<1.36.0)", "mypy-boto3-iotsecuretunneling (>=1.35.0,<1.36.0)", "mypy-boto3-iotsitewise (>=1.35.0,<1.36.0)", "mypy-boto3-iotthingsgraph (>=1.35.0,<1.36.0)", "mypy-boto3-iottwinmaker (>=1.35.0,<1.36.0)", "mypy-boto3-iotwireless (>=1.35.0,<1.36.0)", "mypy-boto3-ivs (>=1.35.0,<1.36.0)", "mypy-boto3-ivs-realtime (>=1.35.0,<1.36.0)", "mypy-boto3-ivschat (>=1.35.0,<1.36.0)", "mypy-boto3-kafka (>=1.35.0,<1.36.0)", "mypy-boto3-kafkaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-kendra (>=1.35.0,<1.36.0)", "mypy-boto3-kendra-ranking (>=1.35.0,<1.36.0)", "mypy-boto3-keyspaces (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-archived-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-signaling (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisvideo (>=1.35.0,<1.36.0)", "mypy-boto3-kms (>=1.35.0,<1.36.0)", "mypy-boto3-lakeformation (>=1.35.0,<1.36.0)", "mypy-boto3-lambda (>=1.35.0,<1.36.0)", "mypy-boto3-launch-wizard (>=1.35.0,<1.36.0)", "mypy-boto3-lex-models (>=1.35.0,<1.36.0)", "mypy-boto3-lex-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-models (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-lightsail (>=1.35.0,<1.36.0)", "mypy-boto3-location (>=1.35.0,<1.36.0)", "mypy-boto3-logs (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutequipment (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutmetrics (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutvision (>=1.35.0,<1.36.0)", "mypy-boto3-m2 (>=1.35.0,<1.36.0)", "mypy-boto3-machinelearning (>=1.35.0,<1.36.0)", "mypy-boto3-macie2 (>=1.35.0,<1.36.0)", "mypy-boto3-mailmanager (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain-query (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-agreement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-catalog (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-deployment (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-entitlement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconvert (>=1.35.0,<1.36.0)", "mypy-boto3-medialive (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage-vod (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackagev2 (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore-data (>=1.35.0,<1.36.0)", "mypy-boto3-mediatailor (>=1.35.0,<1.36.0)", "mypy-boto3-medical-imaging (>=1.35.0,<1.36.0)", "mypy-boto3-memorydb (>=1.35.0,<1.36.0)", "mypy-boto3-meteringmarketplace (>=1.35.0,<1.36.0)", "mypy-boto3-mgh (>=1.35.0,<1.36.0)", "mypy-boto3-mgn (>=1.35.0,<1.36.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhub-config (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhuborchestrator (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhubstrategy (>=1.35.0,<1.36.0)", "mypy-boto3-mq (>=1.35.0,<1.36.0)", "mypy-boto3-mturk (>=1.35.0,<1.36.0)", "mypy-boto3-mwaa (>=1.35.0,<1.36.0)", "mypy-boto3-neptune (>=1.35.0,<1.36.0)", "mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)", "mypy-boto3-neptunedata (>=1.35.0,<1.36.0)", "mypy-boto3-network-firewall (>=1.35.0,<1.36.0)", "mypy-boto3-networkmanager (>=1.35.0,<1.36.0)", "mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-nimble (>=1.35.0,<1.36.0)", "mypy-boto3-oam (>=1.35.0,<1.36.0)", "mypy-boto3-omics (>=1.35.0,<1.36.0)", "mypy-boto3-opensearch (>=1.35.0,<1.36.0)", "mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)", "mypy-boto3-opsworks (>=1.35.0,<1.36.0)", "mypy-boto3-opsworkscm (>=1.35.0,<1.36.0)", "mypy-boto3-organizations (>=1.35.0,<1.36.0)", "mypy-boto3-osis (>=1.35.0,<1.36.0)", "mypy-boto3-outposts (>=1.35.0,<1.36.0)", "mypy-boto3-panorama (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-scep (>=1.35.0,<1.36.0)", "mypy-boto3-pcs (>=1.35.0,<1.36.0)", "mypy-boto3-personalize (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-events (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-pi (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-email (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.35.0,<1.36.0)", "mypy-boto3-pipes (>=1.35.0,<1.36.0)", "mypy-boto3-polly (>=1.35.0,<1.36.0)", "mypy-boto3-pricing (>=1.35.0,<1.36.0)", "mypy-boto3-privatenetworks (>=1.35.0,<1.36.0)", "mypy-boto3-proton (>=1.35.0,<1.36.0)", "mypy-boto3-qapps (>=1.35.0,<1.36.0)", "mypy-boto3-qbusiness (>=1.35.0,<1.36.0)", "mypy-boto3-qconnect (>=1.35.0,<1.36.0)", "mypy-boto3-qldb (>=1.35.0,<1.36.0)", "mypy-boto3-qldb-session (>=1.35.0,<1.36.0)", "mypy-boto3-quicksight (>=1.35.0,<1.36.0)", "mypy-boto3-ram (>=1.35.0,<1.36.0)", "mypy-boto3-rbin (>=1.35.0,<1.36.0)", "mypy-boto3-rds (>=1.35.0,<1.36.0)", "mypy-boto3-rds-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-rekognition (>=1.35.0,<1.36.0)", "mypy-boto3-repostspace (>=1.35.0,<1.36.0)", "mypy-boto3-resiliencehub (>=1.35.0,<1.36.0)", "mypy-boto3-resource-explorer-2 (>=1.35.0,<1.36.0)", "mypy-boto3-resource-groups (>=1.35.0,<1.36.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.35.0,<1.36.0)", "mypy-boto3-robomaker (>=1.35.0,<1.36.0)", "mypy-boto3-rolesanywhere (>=1.35.0,<1.36.0)", "mypy-boto3-route53 (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-cluster (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-control-config (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-readiness (>=1.35.0,<1.36.0)", "mypy-boto3-route53domains (>=1.35.0,<1.36.0)", "mypy-boto3-route53profiles (>=1.35.0,<1.36.0)", "mypy-boto3-route53resolver (>=1.35.0,<1.36.0)", "mypy-boto3-rum (>=1.35.0,<1.36.0)", "mypy-boto3-s3 (>=1.35.0,<1.36.0)", "mypy-boto3-s3control (>=1.35.0,<1.36.0)", "mypy-boto3-s3outposts (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-geospatial (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-metrics (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-savingsplans (>=1.35.0,<1.36.0)", "mypy-boto3-scheduler (>=1.35.0,<1.36.0)", "mypy-boto3-schemas (>=1.35.0,<1.36.0)", "mypy-boto3-sdb (>=1.35.0,<1.36.0)", "mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)", "mypy-boto3-securityhub (>=1.35.0,<1.36.0)", "mypy-boto3-securitylake (>=1.35.0,<1.36.0)", "mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)", "mypy-boto3-service-quotas (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog-appregistry (>=1.35.0,<1.36.0)", "mypy-boto3-servicediscovery (>=1.35.0,<1.36.0)", "mypy-boto3-ses (>=1.35.0,<1.36.0)", "mypy-boto3-sesv2 (>=1.35.0,<1.36.0)", "mypy-boto3-shield (>=1.35.0,<1.36.0)", "mypy-boto3-signer (>=1.35.0,<1.36.0)", "mypy-boto3-simspaceweaver (>=1.35.0,<1.36.0)", "mypy-boto3-sms (>=1.35.0,<1.36.0)", "mypy-boto3-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-snow-device-management (>=1.35.0,<1.36.0)", "mypy-boto3-snowball (>=1.35.0,<1.36.0)", "mypy-boto3-sns (>=1.35.0,<1.36.0)", "mypy-boto3-sqs (>=1.35.0,<1.36.0)", "mypy-boto3-ssm (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-contacts (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-incidents (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-quicksetup (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-sap (>=1.35.0,<1.36.0)", "mypy-boto3-sso (>=1.35.0,<1.36.0)", "mypy-boto3-sso-admin (>=1.35.0,<1.36.0)", "mypy-boto3-sso-oidc (>=1.35.0,<1.36.0)", "mypy-boto3-stepfunctions (>=1.35.0,<1.36.0)", "mypy-boto3-storagegateway (>=1.35.0,<1.36.0)", "mypy-boto3-sts (>=1.35.0,<1.36.0)", "mypy-boto3-supplychain (>=1.35.0,<1.36.0)", "mypy-boto3-support (>=1.35.0,<1.36.0)", "mypy-boto3-support-app (>=1.35.0,<1.36.0)", "mypy-boto3-swf (>=1.35.0,<1.36.0)", "mypy-boto3-synthetics (>=1.35.0,<1.36.0)", "mypy-boto3-taxsettings (>=1.35.0,<1.36.0)", "mypy-boto3-textract (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-influxdb (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-query (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-write (>=1.35.0,<1.36.0)", "mypy-boto3-tnb (>=1.35.0,<1.36.0)", "mypy-boto3-transcribe (>=1.35.0,<1.36.0)", "mypy-boto3-transfer (>=1.35.0,<1.36.0)", "mypy-boto3-translate (>=1.35.0,<1.36.0)", "mypy-boto3-trustedadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-verifiedpermissions (>=1.35.0,<1.36.0)", "mypy-boto3-voice-id (>=1.35.0,<1.36.0)", "mypy-boto3-vpc-lattice (>=1.35.0,<1.36.0)", "mypy-boto3-waf (>=1.35.0,<1.36.0)", "mypy-boto3-waf-regional (>=1.35.0,<1.36.0)", "mypy-boto3-wafv2 (>=1.35.0,<1.36.0)", "mypy-boto3-wellarchitected (>=1.35.0,<1.36.0)", "mypy-boto3-wisdom (>=1.35.0,<1.36.0)", "mypy-boto3-workdocs (>=1.35.0,<1.36.0)", "mypy-boto3-worklink (>=1.35.0,<1.36.0)", "mypy-boto3-workmail (>=1.35.0,<1.36.0)", "mypy-boto3-workmailmessageflow (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-thin-client (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-web (>=1.35.0,<1.36.0)", "mypy-boto3-xray (>=1.35.0,<1.36.0)"] +all = ["mypy-boto3-accessanalyzer (>=1.35.0,<1.36.0)", "mypy-boto3-account (>=1.35.0,<1.36.0)", "mypy-boto3-acm (>=1.35.0,<1.36.0)", "mypy-boto3-acm-pca (>=1.35.0,<1.36.0)", "mypy-boto3-amp (>=1.35.0,<1.36.0)", "mypy-boto3-amplify (>=1.35.0,<1.36.0)", "mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)", "mypy-boto3-amplifyuibuilder (>=1.35.0,<1.36.0)", "mypy-boto3-apigateway (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewaymanagementapi (>=1.35.0,<1.36.0)", "mypy-boto3-apigatewayv2 (>=1.35.0,<1.36.0)", "mypy-boto3-appconfig (>=1.35.0,<1.36.0)", "mypy-boto3-appconfigdata (>=1.35.0,<1.36.0)", "mypy-boto3-appfabric (>=1.35.0,<1.36.0)", "mypy-boto3-appflow (>=1.35.0,<1.36.0)", "mypy-boto3-appintegrations (>=1.35.0,<1.36.0)", "mypy-boto3-application-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-application-insights (>=1.35.0,<1.36.0)", "mypy-boto3-application-signals (>=1.35.0,<1.36.0)", "mypy-boto3-applicationcostprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-appmesh (>=1.35.0,<1.36.0)", "mypy-boto3-apprunner (>=1.35.0,<1.36.0)", "mypy-boto3-appstream (>=1.35.0,<1.36.0)", "mypy-boto3-appsync (>=1.35.0,<1.36.0)", "mypy-boto3-apptest (>=1.35.0,<1.36.0)", "mypy-boto3-arc-zonal-shift (>=1.35.0,<1.36.0)", "mypy-boto3-artifact (>=1.35.0,<1.36.0)", "mypy-boto3-athena (>=1.35.0,<1.36.0)", "mypy-boto3-auditmanager (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling (>=1.35.0,<1.36.0)", "mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)", "mypy-boto3-b2bi (>=1.35.0,<1.36.0)", "mypy-boto3-backup (>=1.35.0,<1.36.0)", "mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)", "mypy-boto3-batch (>=1.35.0,<1.36.0)", "mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-billingconductor (>=1.35.0,<1.36.0)", "mypy-boto3-braket (>=1.35.0,<1.36.0)", "mypy-boto3-budgets (>=1.35.0,<1.36.0)", "mypy-boto3-ce (>=1.35.0,<1.36.0)", "mypy-boto3-chatbot (>=1.35.0,<1.36.0)", "mypy-boto3-chime (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-identity (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-meetings (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-messaging (>=1.35.0,<1.36.0)", "mypy-boto3-chime-sdk-voice (>=1.35.0,<1.36.0)", "mypy-boto3-cleanrooms (>=1.35.0,<1.36.0)", "mypy-boto3-cleanroomsml (>=1.35.0,<1.36.0)", "mypy-boto3-cloud9 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudcontrol (>=1.35.0,<1.36.0)", "mypy-boto3-clouddirectory (>=1.35.0,<1.36.0)", "mypy-boto3-cloudformation (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront (>=1.35.0,<1.36.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsm (>=1.35.0,<1.36.0)", "mypy-boto3-cloudhsmv2 (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearch (>=1.35.0,<1.36.0)", "mypy-boto3-cloudsearchdomain (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail (>=1.35.0,<1.36.0)", "mypy-boto3-cloudtrail-data (>=1.35.0,<1.36.0)", "mypy-boto3-cloudwatch (>=1.35.0,<1.36.0)", "mypy-boto3-codeartifact (>=1.35.0,<1.36.0)", "mypy-boto3-codebuild (>=1.35.0,<1.36.0)", "mypy-boto3-codecatalyst (>=1.35.0,<1.36.0)", "mypy-boto3-codecommit (>=1.35.0,<1.36.0)", "mypy-boto3-codeconnections (>=1.35.0,<1.36.0)", "mypy-boto3-codedeploy (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-reviewer (>=1.35.0,<1.36.0)", "mypy-boto3-codeguru-security (>=1.35.0,<1.36.0)", "mypy-boto3-codeguruprofiler (>=1.35.0,<1.36.0)", "mypy-boto3-codepipeline (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-connections (>=1.35.0,<1.36.0)", "mypy-boto3-codestar-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-identity (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-idp (>=1.35.0,<1.36.0)", "mypy-boto3-cognito-sync (>=1.35.0,<1.36.0)", "mypy-boto3-comprehend (>=1.35.0,<1.36.0)", "mypy-boto3-comprehendmedical (>=1.35.0,<1.36.0)", "mypy-boto3-compute-optimizer (>=1.35.0,<1.36.0)", "mypy-boto3-config (>=1.35.0,<1.36.0)", "mypy-boto3-connect (>=1.35.0,<1.36.0)", "mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)", "mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)", "mypy-boto3-connectcases (>=1.35.0,<1.36.0)", "mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)", "mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)", "mypy-boto3-controltower (>=1.35.0,<1.36.0)", "mypy-boto3-cost-optimization-hub (>=1.35.0,<1.36.0)", "mypy-boto3-cur (>=1.35.0,<1.36.0)", "mypy-boto3-customer-profiles (>=1.35.0,<1.36.0)", "mypy-boto3-databrew (>=1.35.0,<1.36.0)", "mypy-boto3-dataexchange (>=1.35.0,<1.36.0)", "mypy-boto3-datapipeline (>=1.35.0,<1.36.0)", "mypy-boto3-datasync (>=1.35.0,<1.36.0)", "mypy-boto3-datazone (>=1.35.0,<1.36.0)", "mypy-boto3-dax (>=1.35.0,<1.36.0)", "mypy-boto3-deadline (>=1.35.0,<1.36.0)", "mypy-boto3-detective (>=1.35.0,<1.36.0)", "mypy-boto3-devicefarm (>=1.35.0,<1.36.0)", "mypy-boto3-devops-guru (>=1.35.0,<1.36.0)", "mypy-boto3-directconnect (>=1.35.0,<1.36.0)", "mypy-boto3-discovery (>=1.35.0,<1.36.0)", "mypy-boto3-dlm (>=1.35.0,<1.36.0)", "mypy-boto3-dms (>=1.35.0,<1.36.0)", "mypy-boto3-docdb (>=1.35.0,<1.36.0)", "mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)", "mypy-boto3-drs (>=1.35.0,<1.36.0)", "mypy-boto3-ds (>=1.35.0,<1.36.0)", "mypy-boto3-ds-data (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodb (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)", "mypy-boto3-ebs (>=1.35.0,<1.36.0)", "mypy-boto3-ec2 (>=1.35.0,<1.36.0)", "mypy-boto3-ec2-instance-connect (>=1.35.0,<1.36.0)", "mypy-boto3-ecr (>=1.35.0,<1.36.0)", "mypy-boto3-ecr-public (>=1.35.0,<1.36.0)", "mypy-boto3-ecs (>=1.35.0,<1.36.0)", "mypy-boto3-efs (>=1.35.0,<1.36.0)", "mypy-boto3-eks (>=1.35.0,<1.36.0)", "mypy-boto3-eks-auth (>=1.35.0,<1.36.0)", "mypy-boto3-elastic-inference (>=1.35.0,<1.36.0)", "mypy-boto3-elasticache (>=1.35.0,<1.36.0)", "mypy-boto3-elasticbeanstalk (>=1.35.0,<1.36.0)", "mypy-boto3-elastictranscoder (>=1.35.0,<1.36.0)", "mypy-boto3-elb (>=1.35.0,<1.36.0)", "mypy-boto3-elbv2 (>=1.35.0,<1.36.0)", "mypy-boto3-emr (>=1.35.0,<1.36.0)", "mypy-boto3-emr-containers (>=1.35.0,<1.36.0)", "mypy-boto3-emr-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-entityresolution (>=1.35.0,<1.36.0)", "mypy-boto3-es (>=1.35.0,<1.36.0)", "mypy-boto3-events (>=1.35.0,<1.36.0)", "mypy-boto3-evidently (>=1.35.0,<1.36.0)", "mypy-boto3-finspace (>=1.35.0,<1.36.0)", "mypy-boto3-finspace-data (>=1.35.0,<1.36.0)", "mypy-boto3-firehose (>=1.35.0,<1.36.0)", "mypy-boto3-fis (>=1.35.0,<1.36.0)", "mypy-boto3-fms (>=1.35.0,<1.36.0)", "mypy-boto3-forecast (>=1.35.0,<1.36.0)", "mypy-boto3-forecastquery (>=1.35.0,<1.36.0)", "mypy-boto3-frauddetector (>=1.35.0,<1.36.0)", "mypy-boto3-freetier (>=1.35.0,<1.36.0)", "mypy-boto3-fsx (>=1.35.0,<1.36.0)", "mypy-boto3-gamelift (>=1.35.0,<1.36.0)", "mypy-boto3-glacier (>=1.35.0,<1.36.0)", "mypy-boto3-globalaccelerator (>=1.35.0,<1.36.0)", "mypy-boto3-glue (>=1.35.0,<1.36.0)", "mypy-boto3-grafana (>=1.35.0,<1.36.0)", "mypy-boto3-greengrass (>=1.35.0,<1.36.0)", "mypy-boto3-greengrassv2 (>=1.35.0,<1.36.0)", "mypy-boto3-groundstation (>=1.35.0,<1.36.0)", "mypy-boto3-guardduty (>=1.35.0,<1.36.0)", "mypy-boto3-health (>=1.35.0,<1.36.0)", "mypy-boto3-healthlake (>=1.35.0,<1.36.0)", "mypy-boto3-iam (>=1.35.0,<1.36.0)", "mypy-boto3-identitystore (>=1.35.0,<1.36.0)", "mypy-boto3-imagebuilder (>=1.35.0,<1.36.0)", "mypy-boto3-importexport (>=1.35.0,<1.36.0)", "mypy-boto3-inspector (>=1.35.0,<1.36.0)", "mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)", "mypy-boto3-inspector2 (>=1.35.0,<1.36.0)", "mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-iot (>=1.35.0,<1.36.0)", "mypy-boto3-iot-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-devices (>=1.35.0,<1.36.0)", "mypy-boto3-iot1click-projects (>=1.35.0,<1.36.0)", "mypy-boto3-iotanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-iotdeviceadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents (>=1.35.0,<1.36.0)", "mypy-boto3-iotevents-data (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleethub (>=1.35.0,<1.36.0)", "mypy-boto3-iotfleetwise (>=1.35.0,<1.36.0)", "mypy-boto3-iotsecuretunneling (>=1.35.0,<1.36.0)", "mypy-boto3-iotsitewise (>=1.35.0,<1.36.0)", "mypy-boto3-iotthingsgraph (>=1.35.0,<1.36.0)", "mypy-boto3-iottwinmaker (>=1.35.0,<1.36.0)", "mypy-boto3-iotwireless (>=1.35.0,<1.36.0)", "mypy-boto3-ivs (>=1.35.0,<1.36.0)", "mypy-boto3-ivs-realtime (>=1.35.0,<1.36.0)", "mypy-boto3-ivschat (>=1.35.0,<1.36.0)", "mypy-boto3-kafka (>=1.35.0,<1.36.0)", "mypy-boto3-kafkaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-kendra (>=1.35.0,<1.36.0)", "mypy-boto3-kendra-ranking (>=1.35.0,<1.36.0)", "mypy-boto3-keyspaces (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-archived-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-media (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-signaling (>=1.35.0,<1.36.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.35.0,<1.36.0)", "mypy-boto3-kinesisvideo (>=1.35.0,<1.36.0)", "mypy-boto3-kms (>=1.35.0,<1.36.0)", "mypy-boto3-lakeformation (>=1.35.0,<1.36.0)", "mypy-boto3-lambda (>=1.35.0,<1.36.0)", "mypy-boto3-launch-wizard (>=1.35.0,<1.36.0)", "mypy-boto3-lex-models (>=1.35.0,<1.36.0)", "mypy-boto3-lex-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-models (>=1.35.0,<1.36.0)", "mypy-boto3-lexv2-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.35.0,<1.36.0)", "mypy-boto3-lightsail (>=1.35.0,<1.36.0)", "mypy-boto3-location (>=1.35.0,<1.36.0)", "mypy-boto3-logs (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutequipment (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutmetrics (>=1.35.0,<1.36.0)", "mypy-boto3-lookoutvision (>=1.35.0,<1.36.0)", "mypy-boto3-m2 (>=1.35.0,<1.36.0)", "mypy-boto3-machinelearning (>=1.35.0,<1.36.0)", "mypy-boto3-macie2 (>=1.35.0,<1.36.0)", "mypy-boto3-mailmanager (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain (>=1.35.0,<1.36.0)", "mypy-boto3-managedblockchain-query (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-agreement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-catalog (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-deployment (>=1.35.0,<1.36.0)", "mypy-boto3-marketplace-entitlement (>=1.35.0,<1.36.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconnect (>=1.35.0,<1.36.0)", "mypy-boto3-mediaconvert (>=1.35.0,<1.36.0)", "mypy-boto3-medialive (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackage-vod (>=1.35.0,<1.36.0)", "mypy-boto3-mediapackagev2 (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore (>=1.35.0,<1.36.0)", "mypy-boto3-mediastore-data (>=1.35.0,<1.36.0)", "mypy-boto3-mediatailor (>=1.35.0,<1.36.0)", "mypy-boto3-medical-imaging (>=1.35.0,<1.36.0)", "mypy-boto3-memorydb (>=1.35.0,<1.36.0)", "mypy-boto3-meteringmarketplace (>=1.35.0,<1.36.0)", "mypy-boto3-mgh (>=1.35.0,<1.36.0)", "mypy-boto3-mgn (>=1.35.0,<1.36.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhub-config (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhuborchestrator (>=1.35.0,<1.36.0)", "mypy-boto3-migrationhubstrategy (>=1.35.0,<1.36.0)", "mypy-boto3-mq (>=1.35.0,<1.36.0)", "mypy-boto3-mturk (>=1.35.0,<1.36.0)", "mypy-boto3-mwaa (>=1.35.0,<1.36.0)", "mypy-boto3-neptune (>=1.35.0,<1.36.0)", "mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)", "mypy-boto3-neptunedata (>=1.35.0,<1.36.0)", "mypy-boto3-network-firewall (>=1.35.0,<1.36.0)", "mypy-boto3-networkmanager (>=1.35.0,<1.36.0)", "mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)", "mypy-boto3-nimble (>=1.35.0,<1.36.0)", "mypy-boto3-oam (>=1.35.0,<1.36.0)", "mypy-boto3-omics (>=1.35.0,<1.36.0)", "mypy-boto3-opensearch (>=1.35.0,<1.36.0)", "mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)", "mypy-boto3-opsworks (>=1.35.0,<1.36.0)", "mypy-boto3-opsworkscm (>=1.35.0,<1.36.0)", "mypy-boto3-organizations (>=1.35.0,<1.36.0)", "mypy-boto3-osis (>=1.35.0,<1.36.0)", "mypy-boto3-outposts (>=1.35.0,<1.36.0)", "mypy-boto3-panorama (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)", "mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)", "mypy-boto3-pca-connector-scep (>=1.35.0,<1.36.0)", "mypy-boto3-pcs (>=1.35.0,<1.36.0)", "mypy-boto3-personalize (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-events (>=1.35.0,<1.36.0)", "mypy-boto3-personalize-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-pi (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-email (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.35.0,<1.36.0)", "mypy-boto3-pipes (>=1.35.0,<1.36.0)", "mypy-boto3-polly (>=1.35.0,<1.36.0)", "mypy-boto3-pricing (>=1.35.0,<1.36.0)", "mypy-boto3-privatenetworks (>=1.35.0,<1.36.0)", "mypy-boto3-proton (>=1.35.0,<1.36.0)", "mypy-boto3-qapps (>=1.35.0,<1.36.0)", "mypy-boto3-qbusiness (>=1.35.0,<1.36.0)", "mypy-boto3-qconnect (>=1.35.0,<1.36.0)", "mypy-boto3-qldb (>=1.35.0,<1.36.0)", "mypy-boto3-qldb-session (>=1.35.0,<1.36.0)", "mypy-boto3-quicksight (>=1.35.0,<1.36.0)", "mypy-boto3-ram (>=1.35.0,<1.36.0)", "mypy-boto3-rbin (>=1.35.0,<1.36.0)", "mypy-boto3-rds (>=1.35.0,<1.36.0)", "mypy-boto3-rds-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-data (>=1.35.0,<1.36.0)", "mypy-boto3-redshift-serverless (>=1.35.0,<1.36.0)", "mypy-boto3-rekognition (>=1.35.0,<1.36.0)", "mypy-boto3-repostspace (>=1.35.0,<1.36.0)", "mypy-boto3-resiliencehub (>=1.35.0,<1.36.0)", "mypy-boto3-resource-explorer-2 (>=1.35.0,<1.36.0)", "mypy-boto3-resource-groups (>=1.35.0,<1.36.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.35.0,<1.36.0)", "mypy-boto3-robomaker (>=1.35.0,<1.36.0)", "mypy-boto3-rolesanywhere (>=1.35.0,<1.36.0)", "mypy-boto3-route53 (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-cluster (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-control-config (>=1.35.0,<1.36.0)", "mypy-boto3-route53-recovery-readiness (>=1.35.0,<1.36.0)", "mypy-boto3-route53domains (>=1.35.0,<1.36.0)", "mypy-boto3-route53profiles (>=1.35.0,<1.36.0)", "mypy-boto3-route53resolver (>=1.35.0,<1.36.0)", "mypy-boto3-rum (>=1.35.0,<1.36.0)", "mypy-boto3-s3 (>=1.35.0,<1.36.0)", "mypy-boto3-s3control (>=1.35.0,<1.36.0)", "mypy-boto3-s3outposts (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-geospatial (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-metrics (>=1.35.0,<1.36.0)", "mypy-boto3-sagemaker-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-savingsplans (>=1.35.0,<1.36.0)", "mypy-boto3-scheduler (>=1.35.0,<1.36.0)", "mypy-boto3-schemas (>=1.35.0,<1.36.0)", "mypy-boto3-sdb (>=1.35.0,<1.36.0)", "mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)", "mypy-boto3-securityhub (>=1.35.0,<1.36.0)", "mypy-boto3-securitylake (>=1.35.0,<1.36.0)", "mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)", "mypy-boto3-service-quotas (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog (>=1.35.0,<1.36.0)", "mypy-boto3-servicecatalog-appregistry (>=1.35.0,<1.36.0)", "mypy-boto3-servicediscovery (>=1.35.0,<1.36.0)", "mypy-boto3-ses (>=1.35.0,<1.36.0)", "mypy-boto3-sesv2 (>=1.35.0,<1.36.0)", "mypy-boto3-shield (>=1.35.0,<1.36.0)", "mypy-boto3-signer (>=1.35.0,<1.36.0)", "mypy-boto3-simspaceweaver (>=1.35.0,<1.36.0)", "mypy-boto3-sms (>=1.35.0,<1.36.0)", "mypy-boto3-sms-voice (>=1.35.0,<1.36.0)", "mypy-boto3-snow-device-management (>=1.35.0,<1.36.0)", "mypy-boto3-snowball (>=1.35.0,<1.36.0)", "mypy-boto3-sns (>=1.35.0,<1.36.0)", "mypy-boto3-sqs (>=1.35.0,<1.36.0)", "mypy-boto3-ssm (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-contacts (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-incidents (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-quicksetup (>=1.35.0,<1.36.0)", "mypy-boto3-ssm-sap (>=1.35.0,<1.36.0)", "mypy-boto3-sso (>=1.35.0,<1.36.0)", "mypy-boto3-sso-admin (>=1.35.0,<1.36.0)", "mypy-boto3-sso-oidc (>=1.35.0,<1.36.0)", "mypy-boto3-stepfunctions (>=1.35.0,<1.36.0)", "mypy-boto3-storagegateway (>=1.35.0,<1.36.0)", "mypy-boto3-sts (>=1.35.0,<1.36.0)", "mypy-boto3-supplychain (>=1.35.0,<1.36.0)", "mypy-boto3-support (>=1.35.0,<1.36.0)", "mypy-boto3-support-app (>=1.35.0,<1.36.0)", "mypy-boto3-swf (>=1.35.0,<1.36.0)", "mypy-boto3-synthetics (>=1.35.0,<1.36.0)", "mypy-boto3-taxsettings (>=1.35.0,<1.36.0)", "mypy-boto3-textract (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-influxdb (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-query (>=1.35.0,<1.36.0)", "mypy-boto3-timestream-write (>=1.35.0,<1.36.0)", "mypy-boto3-tnb (>=1.35.0,<1.36.0)", "mypy-boto3-transcribe (>=1.35.0,<1.36.0)", "mypy-boto3-transfer (>=1.35.0,<1.36.0)", "mypy-boto3-translate (>=1.35.0,<1.36.0)", "mypy-boto3-trustedadvisor (>=1.35.0,<1.36.0)", "mypy-boto3-verifiedpermissions (>=1.35.0,<1.36.0)", "mypy-boto3-voice-id (>=1.35.0,<1.36.0)", "mypy-boto3-vpc-lattice (>=1.35.0,<1.36.0)", "mypy-boto3-waf (>=1.35.0,<1.36.0)", "mypy-boto3-waf-regional (>=1.35.0,<1.36.0)", "mypy-boto3-wafv2 (>=1.35.0,<1.36.0)", "mypy-boto3-wellarchitected (>=1.35.0,<1.36.0)", "mypy-boto3-wisdom (>=1.35.0,<1.36.0)", "mypy-boto3-workdocs (>=1.35.0,<1.36.0)", "mypy-boto3-worklink (>=1.35.0,<1.36.0)", "mypy-boto3-workmail (>=1.35.0,<1.36.0)", "mypy-boto3-workmailmessageflow (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-thin-client (>=1.35.0,<1.36.0)", "mypy-boto3-workspaces-web (>=1.35.0,<1.36.0)", "mypy-boto3-xray (>=1.35.0,<1.36.0)"] amp = ["mypy-boto3-amp (>=1.35.0,<1.36.0)"] amplify = ["mypy-boto3-amplify (>=1.35.0,<1.36.0)"] amplifybackend = ["mypy-boto3-amplifybackend (>=1.35.0,<1.36.0)"] @@ -430,7 +430,7 @@ bedrock-agent = ["mypy-boto3-bedrock-agent (>=1.35.0,<1.36.0)"] bedrock-agent-runtime = ["mypy-boto3-bedrock-agent-runtime (>=1.35.0,<1.36.0)"] bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)"] billingconductor = ["mypy-boto3-billingconductor (>=1.35.0,<1.36.0)"] -boto3 = ["boto3 (==1.35.19)", "botocore (==1.35.19)"] +boto3 = ["boto3 (==1.35.24)", "botocore (==1.35.24)"] braket = ["mypy-boto3-braket (>=1.35.0,<1.36.0)"] budgets = ["mypy-boto3-budgets (>=1.35.0,<1.36.0)"] ce = ["mypy-boto3-ce (>=1.35.0,<1.36.0)"] @@ -503,6 +503,7 @@ docdb = ["mypy-boto3-docdb (>=1.35.0,<1.36.0)"] docdb-elastic = ["mypy-boto3-docdb-elastic (>=1.35.0,<1.36.0)"] drs = ["mypy-boto3-drs (>=1.35.0,<1.36.0)"] ds = ["mypy-boto3-ds (>=1.35.0,<1.36.0)"] +ds-data = ["mypy-boto3-ds-data (>=1.35.0,<1.36.0)"] dynamodb = ["mypy-boto3-dynamodb (>=1.35.0,<1.36.0)"] dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.35.0,<1.36.0)"] ebs = ["mypy-boto3-ebs (>=1.35.0,<1.36.0)"] @@ -538,6 +539,7 @@ forecastquery = ["mypy-boto3-forecastquery (>=1.35.0,<1.36.0)"] frauddetector = ["mypy-boto3-frauddetector (>=1.35.0,<1.36.0)"] freetier = ["mypy-boto3-freetier (>=1.35.0,<1.36.0)"] fsx = ["mypy-boto3-fsx (>=1.35.0,<1.36.0)"] +full = ["boto3-stubs-full"] gamelift = ["mypy-boto3-gamelift (>=1.35.0,<1.36.0)"] glacier = ["mypy-boto3-glacier (>=1.35.0,<1.36.0)"] globalaccelerator = ["mypy-boto3-globalaccelerator (>=1.35.0,<1.36.0)"] @@ -3081,13 +3083,13 @@ mkdocs = ">=1.0.3" [[package]] name = "mkdocs-material" -version = "9.5.34" +version = "9.5.36" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.34-py3-none-any.whl", hash = "sha256:54caa8be708de2b75167fd4d3b9f3d949579294f49cb242515d4653dbee9227e"}, - {file = "mkdocs_material-9.5.34.tar.gz", hash = "sha256:1e60ddf716cfb5679dfd65900b8a25d277064ed82d9a53cd5190e3f894df7840"}, + {file = "mkdocs_material-9.5.36-py3-none-any.whl", hash = "sha256:36734c1fd9404bea74236242ba3359b267fc930c7233b9fd086b0898825d0ac9"}, + {file = "mkdocs_material-9.5.36.tar.gz", hash = "sha256:140456f761320f72b399effc073fa3f8aac744c77b0970797c201cae2f6c967f"}, ] [package.dependencies] @@ -4645,13 +4647,13 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymdown-extensions" -version = "10.9" +version = "10.10.1" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, - {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, + {file = "pymdown_extensions-10.10.1-py3-none-any.whl", hash = "sha256:6c74ea6c2e2285186a241417480fc2d3cc52941b3ec2dced4014c84dc78c5493"}, + {file = "pymdown_extensions-10.10.1.tar.gz", hash = "sha256:ad277ee4739ced051c3b6328d22ce782358a3bec39bc6ca52815ccbf44f7acdc"}, ] [package.dependencies] @@ -4823,13 +4825,13 @@ image = ["Pillow (>=8.0.0)"] [[package]] name = "pyright" -version = "1.1.380" +version = "1.1.381" description = "Command line wrapper for pyright" optional = false python-versions = ">=3.7" files = [ - {file = "pyright-1.1.380-py3-none-any.whl", hash = "sha256:a6404392053d8848bacc7aebcbd9d318bb46baf1a1a000359305481920f43879"}, - {file = "pyright-1.1.380.tar.gz", hash = "sha256:e6ceb1a5f7e9f03106e0aa1d6fbb4d97735a5e7ffb59f3de6b2db590baf935b2"}, + {file = "pyright-1.1.381-py3-none-any.whl", hash = "sha256:5dc0aa80a265675d36abab59c674ae01dbe476714f91845b61b841d34aa99081"}, + {file = "pyright-1.1.381.tar.gz", hash = "sha256:314cf0c1351c189524fb10c7ac20688ecd470e8cc505c394d642c9c80bf7c3a5"}, ] [package.dependencies] @@ -4896,21 +4898,21 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-env" -version = "1.1.4" +version = "1.1.5" description = "pytest plugin that allows you to add environment variables." optional = false python-versions = ">=3.8" files = [ - {file = "pytest_env-1.1.4-py3-none-any.whl", hash = "sha256:a4212056d4d440febef311a98fdca56c31256d58fb453d103cba4e8a532b721d"}, - {file = "pytest_env-1.1.4.tar.gz", hash = "sha256:86653658da8f11c6844975db955746c458a9c09f1e64957603161e2ff93f5133"}, + {file = "pytest_env-1.1.5-py3-none-any.whl", hash = "sha256:ce90cf8772878515c24b31cd97c7fa1f4481cd68d588419fd45f10ecaee6bc30"}, + {file = "pytest_env-1.1.5.tar.gz", hash = "sha256:91209840aa0e43385073ac464a554ad2947cc2fd663a9debf88d03b01e0cc1cf"}, ] [package.dependencies] -pytest = ">=8.3.2" +pytest = ">=8.3.3" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [package.extras] -test = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] [[package]] name = "pytest-mock" @@ -5338,29 +5340,29 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.6.5" +version = "0.6.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:7e4e308f16e07c95fc7753fc1aaac690a323b2bb9f4ec5e844a97bb7fbebd748"}, - {file = "ruff-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:932cd69eefe4daf8c7d92bd6689f7e8182571cb934ea720af218929da7bd7d69"}, - {file = "ruff-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a8d42d11fff8d3143ff4da41742a98f8f233bf8890e9fe23077826818f8d680"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a50af6e828ee692fb10ff2dfe53f05caecf077f4210fae9677e06a808275754f"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:794ada3400a0d0b89e3015f1a7e01f4c97320ac665b7bc3ade24b50b54cb2972"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:381413ec47f71ce1d1c614f7779d88886f406f1fd53d289c77e4e533dc6ea200"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52e75a82bbc9b42e63c08d22ad0ac525117e72aee9729a069d7c4f235fc4d276"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09c72a833fd3551135ceddcba5ebdb68ff89225d30758027280968c9acdc7810"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800c50371bdcb99b3c1551d5691e14d16d6f07063a518770254227f7f6e8c178"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e25ddd9cd63ba1f3bd51c1f09903904a6adf8429df34f17d728a8fa11174253"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7291e64d7129f24d1b0c947ec3ec4c0076e958d1475c61202497c6aced35dd19"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9ad7dfbd138d09d9a7e6931e6a7e797651ce29becd688be8a0d4d5f8177b4b0c"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:005256d977021790cc52aa23d78f06bb5090dc0bfbd42de46d49c201533982ae"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:482c1e6bfeb615eafc5899127b805d28e387bd87db38b2c0c41d271f5e58d8cc"}, - {file = "ruff-0.6.5-py3-none-win32.whl", hash = "sha256:cf4d3fa53644137f6a4a27a2b397381d16454a1566ae5335855c187fbf67e4f5"}, - {file = "ruff-0.6.5-py3-none-win_amd64.whl", hash = "sha256:3e42a57b58e3612051a636bc1ac4e6b838679530235520e8f095f7c44f706ff9"}, - {file = "ruff-0.6.5-py3-none-win_arm64.whl", hash = "sha256:51935067740773afdf97493ba9b8231279e9beef0f2a8079188c4776c25688e0"}, - {file = "ruff-0.6.5.tar.gz", hash = "sha256:4d32d87fab433c0cf285c3683dd4dae63be05fd7a1d65b3f5bf7cdd05a6b96fb"}, + {file = "ruff-0.6.7-py3-none-linux_armv6l.whl", hash = "sha256:08277b217534bfdcc2e1377f7f933e1c7957453e8a79764d004e44c40db923f2"}, + {file = "ruff-0.6.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c6707a32e03b791f4448dc0dce24b636cbcdee4dd5607adc24e5ee73fd86c00a"}, + {file = "ruff-0.6.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:533d66b7774ef224e7cf91506a7dafcc9e8ec7c059263ec46629e54e7b1f90ab"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a86aac6f915932d259f7bec79173e356165518859f94649d8c50b81ff087e9"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3f8822defd260ae2460ea3832b24d37d203c3577f48b055590a426a722d50ef"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ba4efe5c6dbbb58be58dd83feedb83b5e95c00091bf09987b4baf510fee5c99"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:525201b77f94d2b54868f0cbe5edc018e64c22563da6c5c2e5c107a4e85c1c0d"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8854450839f339e1049fdbe15d875384242b8e85d5c6947bb2faad33c651020b"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f0b62056246234d59cbf2ea66e84812dc9ec4540518e37553513392c171cb18"}, + {file = "ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b1462fa56c832dc0cea5b4041cfc9c97813505d11cce74ebc6d1aae068de36b"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:02b083770e4cdb1495ed313f5694c62808e71764ec6ee5db84eedd82fd32d8f5"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c05fd37013de36dfa883a3854fae57b3113aaa8abf5dea79202675991d48624"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f49c9caa28d9bbfac4a637ae10327b3db00f47d038f3fbb2195c4d682e925b14"}, + {file = "ruff-0.6.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0e1655868164e114ba43a908fd2d64a271a23660195017c17691fb6355d59bb"}, + {file = "ruff-0.6.7-py3-none-win32.whl", hash = "sha256:a939ca435b49f6966a7dd64b765c9df16f1faed0ca3b6f16acdf7731969deb35"}, + {file = "ruff-0.6.7-py3-none-win_amd64.whl", hash = "sha256:590445eec5653f36248584579c06252ad2e110a5d1f32db5420de35fb0e1c977"}, + {file = "ruff-0.6.7-py3-none-win_arm64.whl", hash = "sha256:b28f0d5e2f771c1fe3c7a45d3f53916fc74a480698c4b5731f0bea61e52137c8"}, + {file = "ruff-0.6.7.tar.gz", hash = "sha256:44e52129d82266fa59b587e2cd74def5637b730a69c4542525dfdecfaae38bd5"}, ] [[package]] @@ -6481,21 +6483,21 @@ files = [ [[package]] name = "typos" -version = "1.24.5" +version = "1.24.6" description = "Source Code Spelling Correction" optional = false python-versions = ">=3.7" files = [ - {file = "typos-1.24.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:95a75c76ecd4aa32b8a18b5aed9f20e4223276851ffa9d77d552533ed3e23198"}, - {file = "typos-1.24.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9a4634eda1082fbe9e7b3fc947870b36b50a964f6b89861ccf19bb9ebf26ddd9"}, - {file = "typos-1.24.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00e1f569ddc8ed80255114cbbbdcb9db278ae738f4ee435ba60803b2c8e7d519"}, - {file = "typos-1.24.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8940a50ad420dc7924e0db520c88cedce2c6cc88f206c621755e5a966c0ad645"}, - {file = "typos-1.24.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1433c987eb2dec6ce627e381870aa36f44cb98696ca4f9ff194abb87bc2075d3"}, - {file = "typos-1.24.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b3e2f44f7f39272ae0cce3f3b89157218db82f5214354d76d3a60f1af0bd0602"}, - {file = "typos-1.24.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b226d2f2960e6a5430a0af30b896e2e067ffa9fe98ea4196c0f514ad97219c47"}, - {file = "typos-1.24.5-py3-none-win32.whl", hash = "sha256:e6a7b77c13e49a5791d3be537eede2e8f4496e662aa7501260344edd5ba7df86"}, - {file = "typos-1.24.5-py3-none-win_amd64.whl", hash = "sha256:47c237a0bbcd8ab432a562020c386abe45f8ea71218b74d800d799d65b39d08b"}, - {file = "typos-1.24.5.tar.gz", hash = "sha256:b31af4d73fd35c6cda7530c5f9d7ca23ecfa11e97d4709783496353cef7e7a73"}, + {file = "typos-1.24.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be576cd0afcbf72bd0fa4129d457b146627c837db189eae7ee83b9fc311dacef"}, + {file = "typos-1.24.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:49fc10b7d28a6a016678c92a5b3d091ea46a2a7e09d5d1122045e8509378f785"}, + {file = "typos-1.24.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfbd7c40af229d680c2b9bc90e846eea70626bde9608f77a57c4e72145a5aa5f"}, + {file = "typos-1.24.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8eb05826d6ff1f8747e1c7d9991a10e13b644b2eb7e2855cc79a37ebb1104f1"}, + {file = "typos-1.24.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2abbe9dc208f6da9fddbf9bb281a3944d66188df9b3d43ad6f2f99721713446"}, + {file = "typos-1.24.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7291555c82e81e305ab3e10cb04d0f7d49ccecc1ced322c60f4619f6a14c7225"}, + {file = "typos-1.24.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7e27c307c26549a7986f2701f161358df29543e818bf9d6d81f0a81ca5ddeff5"}, + {file = "typos-1.24.6-py3-none-win32.whl", hash = "sha256:cd725db3823c319f7e97b4e8e9fa4af143568b1c7d834f66c584bf86b9691f94"}, + {file = "typos-1.24.6-py3-none-win_amd64.whl", hash = "sha256:12972e7a8be14fe5e7f0392de0b228a0098748959d1fecc35c4e8eab3efc04c0"}, + {file = "typos-1.24.6.tar.gz", hash = "sha256:0feda2aab59fc1c32cd1f382ea8676b4ef0921086ab172a43e69e5bb19206993"}, ] [[package]] From e94422f366ca59005eb1b97ebc1d9b675b52f84c Mon Sep 17 00:00:00 2001 From: Matt Vallillo Date: Mon, 23 Sep 2024 16:18:23 -0400 Subject: [PATCH 4/8] Normalize `client` usage (#1173) --- CHANGELOG.md | 26 +++++++ .../openai_audio_transcription_driver.py | 14 ++-- .../amazon_bedrock_cohere_embedding_driver.py | 17 +++-- .../amazon_bedrock_titan_embedding_driver.py | 17 +++-- ...on_sagemaker_jumpstart_embedding_driver.py | 15 +++-- .../azure_openai_embedding_driver.py | 28 ++++---- .../embedding/cohere_embedding_driver.py | 11 +-- .../huggingface_hub_embedding_driver.py | 21 +++--- .../embedding/ollama_embedding_driver.py | 12 ++-- .../embedding/openai_embedding_driver.py | 12 ++-- .../embedding/voyageai_embedding_driver.py | 17 +++-- .../amazon_sqs_event_listener_driver.py | 14 ++-- .../aws_iot_core_event_listener_driver.py | 14 ++-- .../pusher_event_listener_driver.py | 44 ++++++------ .../amazon_s3_file_manager_driver.py | 20 ++++-- .../amazon_bedrock_image_generation_driver.py | 16 +++-- .../azure_openai_image_generation_driver.py | 28 ++++---- .../openai_image_generation_driver.py | 14 ++-- .../amazon_bedrock_image_query_driver.py | 15 +++-- .../anthropic_image_query_driver.py | 20 +++--- .../azure_openai_image_query_driver.py | 28 ++++---- .../image_query/openai_image_query_driver.py | 14 ++-- ...zon_dynamodb_conversation_memory_driver.py | 10 +-- .../prompt/amazon_bedrock_prompt_driver.py | 14 ++-- ...mazon_sagemaker_jumpstart_prompt_driver.py | 12 ++-- .../drivers/prompt/anthropic_prompt_driver.py | 13 ++-- .../prompt/azure_openai_chat_prompt_driver.py | 28 ++++---- .../drivers/prompt/cohere_prompt_driver.py | 13 ++-- .../drivers/prompt/google_prompt_driver.py | 27 ++++---- .../prompt/huggingface_hub_prompt_driver.py | 19 +++--- .../huggingface_pipeline_prompt_driver.py | 24 ++++--- .../drivers/prompt/ollama_prompt_driver.py | 10 +-- .../prompt/openai_chat_prompt_driver.py | 16 +++-- .../drivers/sql/amazon_redshift_sql_driver.py | 13 ++-- griptape/drivers/sql/snowflake_sql_driver.py | 26 +++---- griptape/drivers/sql/sql_driver.py | 10 +-- .../azure_openai_text_to_speech_driver.py | 28 ++++---- .../elevenlabs_text_to_speech_driver.py | 21 +++--- .../openai_text_to_speech_driver.py | 18 +++-- .../amazon_opensearch_vector_store_driver.py | 14 ---- .../vector/astradb_vector_store_driver.py | 47 +++++++------ .../vector/marqo_vector_store_driver.py | 38 +++++------ .../mongodb_atlas_vector_store_driver.py | 14 ++-- .../vector/opensearch_vector_store_driver.py | 29 ++++---- .../vector/pgvector_vector_store_driver.py | 28 +++----- .../vector/pinecone_vector_store_driver.py | 13 ++-- .../vector/qdrant_vector_store_driver.py | 13 +++- .../vector/redis_vector_store_driver.py | 27 ++++---- .../duck_duck_go_web_search_driver.py | 9 ++- griptape/schemas/base_schema.py | 7 ++ griptape/tokenizers/google_tokenizer.py | 17 +++-- griptape/tools/aws_iam/tool.py | 22 +++--- griptape/tools/aws_s3/tool.py | 28 ++++---- poetry.lock | 67 ++++++++++++++++++- pyproject.toml | 2 +- .../test_pusher_event_listener_driver.py | 12 ++-- ...table_diffusion_image_generation_driver.py | 8 +-- .../test_amazon_bedrock_image_query_driver.py | 10 +-- .../vector/test_marqo_vector_store_driver.py | 2 +- .../test_pinecone_vector_storage_driver.py | 19 ++++-- .../vector/test_qdrant_vector_store_driver.py | 24 ------- 61 files changed, 656 insertions(+), 513 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d8ddcf43..289ec72d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## Added +- Parameter `pipeline_task` on `HuggingFacePipelinePromptDriver` for creating different types of `Pipeline`s. + +### Changed +- **BREAKING**: Renamed parameters on several classes to `client`: + - `bedrock_client` on `AmazonBedrockCohereEmbeddingDriver`. + - `bedrock_client` on `AmazonBedrockCohereEmbeddingDriver`. + - `bedrock_client` on `AmazonBedrockTitanEmbeddingDriver`. + - `bedrock_client` on `AmazonBedrockImageGenerationDriver`. + - `bedrock_client` on `AmazonBedrockImageQueryDriver`. + - `bedrock_client` on `AmazonBedrockPromptDriver`. + - `sagemaker_client` on `AmazonSageMakerJumpstartEmbeddingDriver`. + - `sagemaker_client` on `AmazonSageMakerJumpstartPromptDriver`. + - `sqs_client` on `AmazonSqsEventListenerDriver`. + - `iotdata_client` on `AwsIotCoreEventListenerDriver`. + - `s3_client` on `AmazonS3FileManagerDriver`. + - `s3_client` on `AwsS3Tool`. + - `iam_client` on `AwsIamTool`. + - `pusher_client` on `PusherEventListenerDriver`. + - `mq` on `MarqoVectorStoreDriver`. + - `model_client` on `GooglePromptDriver`. + - `model_client` on `GoogleTokenizer`. +- **BREAKING**: Renamed parameter `pipe` on `HuggingFacePipelinePromptDriver` to `pipeline`. +- Several places where API clients are initialized are now lazy loaded. + + ## [0.32.0] - 2024-09-17 ### Added diff --git a/griptape/drivers/audio_transcription/openai_audio_transcription_driver.py b/griptape/drivers/audio_transcription/openai_audio_transcription_driver.py index 312fa83187..f81031897a 100644 --- a/griptape/drivers/audio_transcription/openai_audio_transcription_driver.py +++ b/griptape/drivers/audio_transcription/openai_audio_transcription_driver.py @@ -4,10 +4,11 @@ from typing import Optional import openai -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts import AudioArtifact, TextArtifact from griptape.drivers import BaseAudioTranscriptionDriver +from griptape.utils.decorators import lazy_property @define @@ -17,12 +18,11 @@ class OpenAiAudioTranscriptionDriver(BaseAudioTranscriptionDriver): base_url: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) organization: Optional[str] = field(default=openai.organization, kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization) def try_run(self, audio: AudioArtifact, prompts: Optional[list[str]] = None) -> TextArtifact: additional_params = {} diff --git a/griptape/drivers/embedding/amazon_bedrock_cohere_embedding_driver.py b/griptape/drivers/embedding/amazon_bedrock_cohere_embedding_driver.py index 4e4f4aa31d..c1b2069c85 100644 --- a/griptape/drivers/embedding/amazon_bedrock_cohere_embedding_driver.py +++ b/griptape/drivers/embedding/amazon_bedrock_cohere_embedding_driver.py @@ -1,16 +1,18 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Factory, define, field from griptape.drivers import BaseEmbeddingDriver from griptape.tokenizers.amazon_bedrock_tokenizer import AmazonBedrockTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_bedrock import BedrockClient from griptape.tokenizers.base_tokenizer import BaseTokenizer @@ -26,7 +28,7 @@ class AmazonBedrockCohereEmbeddingDriver(BaseEmbeddingDriver): `search_query` when querying your vector DB to find relevant documents. session: Optionally provide custom `boto3.Session`. tokenizer: Optionally provide custom `BedrockCohereTokenizer`. - bedrock_client: Optionally provide custom `bedrock-runtime` client. + client: Optionally provide custom `bedrock-runtime` client. """ DEFAULT_MODEL = "cohere.embed-english-v3" @@ -38,15 +40,16 @@ class AmazonBedrockCohereEmbeddingDriver(BaseEmbeddingDriver): default=Factory(lambda self: AmazonBedrockTokenizer(model=self.model), takes_self=True), kw_only=True, ) - bedrock_client: Any = field( - default=Factory(lambda self: self.session.client("bedrock-runtime"), takes_self=True), - kw_only=True, - ) + _client: BedrockClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> BedrockClient: + return self.session.client("bedrock-runtime") def try_embed_chunk(self, chunk: str) -> list[float]: payload = {"input_type": self.input_type, "texts": [chunk]} - response = self.bedrock_client.invoke_model( + response = self.client.invoke_model( body=json.dumps(payload), modelId=self.model, accept="*/*", diff --git a/griptape/drivers/embedding/amazon_bedrock_titan_embedding_driver.py b/griptape/drivers/embedding/amazon_bedrock_titan_embedding_driver.py index 5900d7d86b..a17af9aee2 100644 --- a/griptape/drivers/embedding/amazon_bedrock_titan_embedding_driver.py +++ b/griptape/drivers/embedding/amazon_bedrock_titan_embedding_driver.py @@ -1,16 +1,18 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Factory, define, field from griptape.drivers import BaseEmbeddingDriver from griptape.tokenizers.amazon_bedrock_tokenizer import AmazonBedrockTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_bedrock import BedrockClient from griptape.tokenizers.base_tokenizer import BaseTokenizer @@ -23,7 +25,7 @@ class AmazonBedrockTitanEmbeddingDriver(BaseEmbeddingDriver): model: Embedding model name. Defaults to DEFAULT_MODEL. tokenizer: Optionally provide custom `BedrockTitanTokenizer`. session: Optionally provide custom `boto3.Session`. - bedrock_client: Optionally provide custom `bedrock-runtime` client. + client: Optionally provide custom `bedrock-runtime` client. """ DEFAULT_MODEL = "amazon.titan-embed-text-v1" @@ -34,15 +36,16 @@ class AmazonBedrockTitanEmbeddingDriver(BaseEmbeddingDriver): default=Factory(lambda self: AmazonBedrockTokenizer(model=self.model), takes_self=True), kw_only=True, ) - bedrock_client: Any = field( - default=Factory(lambda self: self.session.client("bedrock-runtime"), takes_self=True), - kw_only=True, - ) + _client: BedrockClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> BedrockClient: + return self.session.client("bedrock-runtime") def try_embed_chunk(self, chunk: str) -> list[float]: payload = {"inputText": chunk} - response = self.bedrock_client.invoke_model( + response = self.client.invoke_model( body=json.dumps(payload), modelId=self.model, accept="application/json", diff --git a/griptape/drivers/embedding/amazon_sagemaker_jumpstart_embedding_driver.py b/griptape/drivers/embedding/amazon_sagemaker_jumpstart_embedding_driver.py index c4feb8a1df..c047236de6 100644 --- a/griptape/drivers/embedding/amazon_sagemaker_jumpstart_embedding_driver.py +++ b/griptape/drivers/embedding/amazon_sagemaker_jumpstart_embedding_driver.py @@ -1,32 +1,35 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Optional from attrs import Factory, define, field from griptape.drivers import BaseEmbeddingDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_sagemaker import SageMakerClient @define class AmazonSageMakerJumpstartEmbeddingDriver(BaseEmbeddingDriver): session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - sagemaker_client: Any = field( - default=Factory(lambda self: self.session.client("sagemaker-runtime"), takes_self=True), - kw_only=True, - ) endpoint: str = field(kw_only=True, metadata={"serializable": True}) custom_attributes: str = field(default="accept_eula=true", kw_only=True, metadata={"serializable": True}) inference_component_name: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) + _client: SageMakerClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> SageMakerClient: + return self.session.client("sagemaker-runtime") def try_embed_chunk(self, chunk: str) -> list[float]: payload = {"text_inputs": chunk, "mode": "embedding"} - endpoint_response = self.sagemaker_client.invoke_endpoint( + endpoint_response = self.client.invoke_endpoint( EndpointName=self.endpoint, ContentType="application/json", Body=json.dumps(payload).encode("utf-8"), diff --git a/griptape/drivers/embedding/azure_openai_embedding_driver.py b/griptape/drivers/embedding/azure_openai_embedding_driver.py index c1e601aef4..366a91460f 100644 --- a/griptape/drivers/embedding/azure_openai_embedding_driver.py +++ b/griptape/drivers/embedding/azure_openai_embedding_driver.py @@ -7,6 +7,7 @@ from griptape.drivers import OpenAiEmbeddingDriver from griptape.tokenizers import OpenAiTokenizer +from griptape.utils.decorators import lazy_property @define @@ -40,17 +41,16 @@ class AzureOpenAiEmbeddingDriver(OpenAiEmbeddingDriver): default=Factory(lambda self: OpenAiTokenizer(model=self.model), takes_self=True), kw_only=True, ) - client: openai.AzureOpenAI = field( - default=Factory( - lambda self: openai.AzureOpenAI( - organization=self.organization, - api_key=self.api_key, - api_version=self.api_version, - azure_endpoint=self.azure_endpoint, - azure_deployment=self.azure_deployment, - azure_ad_token=self.azure_ad_token, - azure_ad_token_provider=self.azure_ad_token_provider, - ), - takes_self=True, - ), - ) + _client: openai.AzureOpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.AzureOpenAI: + return openai.AzureOpenAI( + organization=self.organization, + api_key=self.api_key, + api_version=self.api_version, + azure_endpoint=self.azure_endpoint, + azure_deployment=self.azure_deployment, + azure_ad_token=self.azure_ad_token, + azure_ad_token_provider=self.azure_ad_token_provider, + ) diff --git a/griptape/drivers/embedding/cohere_embedding_driver.py b/griptape/drivers/embedding/cohere_embedding_driver.py index 365dc972ed..42e89ff70d 100644 --- a/griptape/drivers/embedding/cohere_embedding_driver.py +++ b/griptape/drivers/embedding/cohere_embedding_driver.py @@ -7,6 +7,7 @@ from griptape.drivers import BaseEmbeddingDriver from griptape.tokenizers import CohereTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from cohere import Client @@ -27,16 +28,16 @@ class CohereEmbeddingDriver(BaseEmbeddingDriver): DEFAULT_MODEL = "models/embedding-001" api_key: str = field(kw_only=True, metadata={"serializable": False}) - client: Client = field( - default=Factory(lambda self: import_optional_dependency("cohere").Client(self.api_key), takes_self=True), - kw_only=True, - ) + input_type: str = field(kw_only=True, metadata={"serializable": True}) + _client: Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) tokenizer: CohereTokenizer = field( default=Factory(lambda self: CohereTokenizer(model=self.model, client=self.client), takes_self=True), kw_only=True, ) - input_type: str = field(kw_only=True, metadata={"serializable": True}) + @lazy_property() + def client(self) -> Client: + return import_optional_dependency("cohere").Client(self.api_key) def try_embed_chunk(self, chunk: str) -> list[float]: result = self.client.embed(texts=[chunk], model=self.model, input_type=self.input_type) diff --git a/griptape/drivers/embedding/huggingface_hub_embedding_driver.py b/griptape/drivers/embedding/huggingface_hub_embedding_driver.py index c1be2ec96e..573bfc3790 100644 --- a/griptape/drivers/embedding/huggingface_hub_embedding_driver.py +++ b/griptape/drivers/embedding/huggingface_hub_embedding_driver.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from griptape.drivers import BaseEmbeddingDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from huggingface_hub import InferenceClient @@ -22,16 +23,14 @@ class HuggingFaceHubEmbeddingDriver(BaseEmbeddingDriver): """ api_token: str = field(kw_only=True, metadata={"serializable": True}) - client: InferenceClient = field( - default=Factory( - lambda self: import_optional_dependency("huggingface_hub").InferenceClient( - model=self.model, - token=self.api_token, - ), - takes_self=True, - ), - kw_only=True, - ) + _client: InferenceClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> InferenceClient: + return import_optional_dependency("huggingface_hub").InferenceClient( + model=self.model, + token=self.api_token, + ) def try_embed_chunk(self, chunk: str) -> list[float]: response = self.client.feature_extraction(chunk) diff --git a/griptape/drivers/embedding/ollama_embedding_driver.py b/griptape/drivers/embedding/ollama_embedding_driver.py index c5c30d5af0..1b32a21f3b 100644 --- a/griptape/drivers/embedding/ollama_embedding_driver.py +++ b/griptape/drivers/embedding/ollama_embedding_driver.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING, Optional -from attrs import Factory, define, field +from attrs import define, field from griptape.drivers import BaseEmbeddingDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from ollama import Client @@ -23,10 +24,11 @@ class OllamaEmbeddingDriver(BaseEmbeddingDriver): model: str = field(kw_only=True, metadata={"serializable": True}) host: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - client: Client = field( - default=Factory(lambda self: import_optional_dependency("ollama").Client(host=self.host), takes_self=True), - kw_only=True, - ) + _client: Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Client: + return import_optional_dependency("ollama").Client(host=self.host) def try_embed_chunk(self, chunk: str) -> list[float]: return list(self.client.embeddings(model=self.model, prompt=chunk)["embedding"]) diff --git a/griptape/drivers/embedding/openai_embedding_driver.py b/griptape/drivers/embedding/openai_embedding_driver.py index 0995fba68b..b0b799790e 100644 --- a/griptape/drivers/embedding/openai_embedding_driver.py +++ b/griptape/drivers/embedding/openai_embedding_driver.py @@ -7,6 +7,7 @@ from griptape.drivers import BaseEmbeddingDriver from griptape.tokenizers import OpenAiTokenizer +from griptape.utils.decorators import lazy_property @define @@ -33,16 +34,15 @@ class OpenAiEmbeddingDriver(BaseEmbeddingDriver): base_url: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) organization: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) tokenizer: OpenAiTokenizer = field( default=Factory(lambda self: OpenAiTokenizer(model=self.model), takes_self=True), kw_only=True, ) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization) def try_embed_chunk(self, chunk: str) -> list[float]: # Address a performance issue in older ada models diff --git a/griptape/drivers/embedding/voyageai_embedding_driver.py b/griptape/drivers/embedding/voyageai_embedding_driver.py index c5e418ed18..bc4e78bf1b 100644 --- a/griptape/drivers/embedding/voyageai_embedding_driver.py +++ b/griptape/drivers/embedding/voyageai_embedding_driver.py @@ -1,12 +1,16 @@ from __future__ import annotations -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional from attrs import Factory, define, field from griptape.drivers import BaseEmbeddingDriver from griptape.tokenizers import VoyageAiTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property + +if TYPE_CHECKING: + import voyageai @define @@ -25,17 +29,16 @@ class VoyageAiEmbeddingDriver(BaseEmbeddingDriver): model: str = field(default=DEFAULT_MODEL, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) - client: Any = field( - default=Factory( - lambda self: import_optional_dependency("voyageai").Client(api_key=self.api_key), - takes_self=True, - ), - ) tokenizer: VoyageAiTokenizer = field( default=Factory(lambda self: VoyageAiTokenizer(model=self.model, api_key=self.api_key), takes_self=True), kw_only=True, ) input_type: str = field(default="document", kw_only=True, metadata={"serializable": True}) + _client: voyageai.Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Any: + return import_optional_dependency("voyageai").Client(api_key=self.api_key) def try_embed_chunk(self, chunk: str) -> list[float]: return self.client.embed([chunk], model=self.model, input_type=self.input_type).embeddings[0] diff --git a/griptape/drivers/event_listener/amazon_sqs_event_listener_driver.py b/griptape/drivers/event_listener/amazon_sqs_event_listener_driver.py index 4c632cb01e..9030f5d779 100644 --- a/griptape/drivers/event_listener/amazon_sqs_event_listener_driver.py +++ b/griptape/drivers/event_listener/amazon_sqs_event_listener_driver.py @@ -1,25 +1,31 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Factory, define, field from griptape.drivers.event_listener.base_event_listener_driver import BaseEventListenerDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_sqs import SQSClient @define class AmazonSqsEventListenerDriver(BaseEventListenerDriver): queue_url: str = field(kw_only=True) session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - sqs_client: Any = field(default=Factory(lambda self: self.session.client("sqs"), takes_self=True)) + _client: SQSClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> SQSClient: + return self.session.client("sqs") def try_publish_event_payload(self, event_payload: dict) -> None: - self.sqs_client.send_message(QueueUrl=self.queue_url, MessageBody=json.dumps(event_payload)) + self.client.send_message(QueueUrl=self.queue_url, MessageBody=json.dumps(event_payload)) def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> None: entries = [ @@ -27,4 +33,4 @@ def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> No for event_payload in event_payload_batch ] - self.sqs_client.send_message_batch(QueueUrl=self.queue_url, Entries=entries) + self.client.send_message_batch(QueueUrl=self.queue_url, Entries=entries) diff --git a/griptape/drivers/event_listener/aws_iot_core_event_listener_driver.py b/griptape/drivers/event_listener/aws_iot_core_event_listener_driver.py index 3b014aed4c..c3a5a55e79 100644 --- a/griptape/drivers/event_listener/aws_iot_core_event_listener_driver.py +++ b/griptape/drivers/event_listener/aws_iot_core_event_listener_driver.py @@ -1,15 +1,17 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Factory, define, field from griptape.drivers.event_listener.base_event_listener_driver import BaseEventListenerDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_iot_data import IoTDataPlaneClient @define @@ -17,10 +19,14 @@ class AwsIotCoreEventListenerDriver(BaseEventListenerDriver): iot_endpoint: str = field(kw_only=True) topic: str = field(kw_only=True) session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - iotdata_client: Any = field(default=Factory(lambda self: self.session.client("iot-data"), takes_self=True)) + _client: IoTDataPlaneClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> IoTDataPlaneClient: + return self.session.client("iot-data") def try_publish_event_payload(self, event_payload: dict) -> None: - self.iotdata_client.publish(topic=self.topic, payload=json.dumps(event_payload)) + self.client.publish(topic=self.topic, payload=json.dumps(event_payload)) def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> None: - self.iotdata_client.publish(topic=self.topic, payload=json.dumps(event_payload_batch)) + self.client.publish(topic=self.topic, payload=json.dumps(event_payload_batch)) diff --git a/griptape/drivers/event_listener/pusher_event_listener_driver.py b/griptape/drivers/event_listener/pusher_event_listener_driver.py index ce9a4fb34d..33d160b46c 100644 --- a/griptape/drivers/event_listener/pusher_event_listener_driver.py +++ b/griptape/drivers/event_listener/pusher_event_listener_driver.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from griptape.drivers import BaseEventListenerDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from pusher import Pusher @@ -13,25 +14,24 @@ @define class PusherEventListenerDriver(BaseEventListenerDriver): - app_id: str = field(kw_only=True) - key: str = field(kw_only=True) - secret: str = field(kw_only=True) - cluster: str = field(kw_only=True) - channel: str = field(kw_only=True) - event_name: str = field(kw_only=True) - pusher_client: Pusher = field( - default=Factory( - lambda self: import_optional_dependency("pusher").Pusher( - app_id=self.app_id, - key=self.key, - secret=self.secret, - cluster=self.cluster, - ssl=True, - ), - takes_self=True, - ), - kw_only=True, - ) + app_id: str = field(kw_only=True, metadata={"serializable": True}) + key: str = field(kw_only=True, metadata={"serializable": True}) + secret: str = field(kw_only=True, metadata={"serializable": False}) + cluster: str = field(kw_only=True, metadata={"serializable": True}) + channel: str = field(kw_only=True, metadata={"serializable": True}) + event_name: str = field(kw_only=True, metadata={"serializable": True}) + ssl: bool = field(default=True, kw_only=True, metadata={"serializable": True}) + _client: Pusher = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Pusher: + return import_optional_dependency("pusher").Pusher( + app_id=self.app_id, + key=self.key, + secret=self.secret, + cluster=self.cluster, + ssl=self.ssl, + ) def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> None: data = [ @@ -39,7 +39,7 @@ def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> No for event_payload in event_payload_batch ] - self.pusher_client.trigger_batch(data) + self.client.trigger_batch(data) def try_publish_event_payload(self, event_payload: dict) -> None: - self.pusher_client.trigger(channels=self.channel, event_name=self.event_name, data=event_payload) + self.client.trigger(channels=self.channel, event_name=self.event_name, data=event_payload) diff --git a/griptape/drivers/file_manager/amazon_s3_file_manager_driver.py b/griptape/drivers/file_manager/amazon_s3_file_manager_driver.py index 20e432c0b0..1e841866a6 100644 --- a/griptape/drivers/file_manager/amazon_s3_file_manager_driver.py +++ b/griptape/drivers/file_manager/amazon_s3_file_manager_driver.py @@ -1,15 +1,17 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Attribute, Factory, define, field +from griptape.utils.decorators import lazy_property from griptape.utils.import_utils import import_optional_dependency from .base_file_manager_driver import BaseFileManagerDriver if TYPE_CHECKING: import boto3 + from mypy_boto3_s3 import S3Client @define @@ -21,13 +23,17 @@ class AmazonS3FileManagerDriver(BaseFileManagerDriver): bucket: The name of the S3 bucket. workdir: The absolute working directory (must start with "/"). List, load, and save operations will be performed relative to this directory. - s3_client: The S3 client to use for S3 operations. + client: The S3 client to use for S3 operations. """ session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) bucket: str = field(kw_only=True) workdir: str = field(default="/", kw_only=True) - s3_client: Any = field(default=Factory(lambda self: self.session.client("s3"), takes_self=True), kw_only=True) + _client: S3Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> S3Client: + return self.session.client("s3") @workdir.validator # pyright: ignore[reportAttributeAccessIssue] def validate_workdir(self, _: Attribute, workdir: str) -> None: @@ -51,7 +57,7 @@ def try_load_file(self, path: str) -> bytes: raise IsADirectoryError try: - response = self.s3_client.get_object(Bucket=self.bucket, Key=full_key) + response = self.client.get_object(Bucket=self.bucket, Key=full_key) return response["Body"].read() except botocore.exceptions.ClientError as e: if e.response["Error"]["Code"] in {"NoSuchKey", "404"}: @@ -62,7 +68,7 @@ def try_save_file(self, path: str, value: bytes) -> None: full_key = self._to_full_key(path) if self._is_a_directory(full_key): raise IsADirectoryError - self.s3_client.put_object(Bucket=self.bucket, Key=full_key, Body=value) + self.client.put_object(Bucket=self.bucket, Key=full_key, Body=value) def _to_full_key(self, path: str) -> str: path = path.lstrip("/") @@ -90,7 +96,7 @@ def _list_files_and_dirs(self, full_key: str, **kwargs) -> list[str]: if max_items is not None: pagination_config["MaxItems"] = max_items - paginator = self.s3_client.get_paginator("list_objects_v2") + paginator = self.client.get_paginator("list_objects_v2") pages = paginator.paginate( Bucket=self.bucket, Prefix=full_key, @@ -116,7 +122,7 @@ def _is_a_directory(self, full_key: str) -> bool: return True try: - self.s3_client.head_object(Bucket=self.bucket, Key=full_key) + self.client.head_object(Bucket=self.bucket, Key=full_key) except botocore.exceptions.ClientError as e: if e.response["Error"]["Code"] in {"NoSuchKey", "404"}: return len(self._list_files_and_dirs(full_key, max_items=1)) > 0 diff --git a/griptape/drivers/image_generation/amazon_bedrock_image_generation_driver.py b/griptape/drivers/image_generation/amazon_bedrock_image_generation_driver.py index 4db302f6f6..3e69036f61 100644 --- a/griptape/drivers/image_generation/amazon_bedrock_image_generation_driver.py +++ b/griptape/drivers/image_generation/amazon_bedrock_image_generation_driver.py @@ -1,16 +1,18 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Optional from attrs import Factory, define, field from griptape.artifacts import ImageArtifact from griptape.drivers import BaseMultiModelImageGenerationDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_bedrock import BedrockClient @define @@ -20,19 +22,21 @@ class AmazonBedrockImageGenerationDriver(BaseMultiModelImageGenerationDriver): Attributes: model: Bedrock model ID. session: boto3 session. - bedrock_client: Bedrock runtime client. + client: Bedrock runtime client. image_width: Width of output images. Defaults to 512 and must be a multiple of 64. image_height: Height of output images. Defaults to 512 and must be a multiple of 64. seed: Optionally provide a consistent seed to generation requests, increasing consistency in output. """ session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - bedrock_client: Any = field( - default=Factory(lambda self: self.session.client(service_name="bedrock-runtime"), takes_self=True), - ) image_width: int = field(default=512, kw_only=True, metadata={"serializable": True}) image_height: int = field(default=512, kw_only=True, metadata={"serializable": True}) seed: Optional[int] = field(default=None, kw_only=True, metadata={"serializable": True}) + _client: BedrockClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> BedrockClient: + return self.session.client("bedrock-runtime") def try_text_to_image(self, prompts: list[str], negative_prompts: Optional[list[str]] = None) -> ImageArtifact: request = self.image_generation_model_driver.text_to_image_request_parameters( @@ -127,7 +131,7 @@ def try_image_outpainting( ) def _make_request(self, request: dict) -> bytes: - response = self.bedrock_client.invoke_model( + response = self.client.invoke_model( body=json.dumps(request), modelId=self.model, accept="application/json", diff --git a/griptape/drivers/image_generation/azure_openai_image_generation_driver.py b/griptape/drivers/image_generation/azure_openai_image_generation_driver.py index 85facda4c1..2555fcfd0c 100644 --- a/griptape/drivers/image_generation/azure_openai_image_generation_driver.py +++ b/griptape/drivers/image_generation/azure_openai_image_generation_driver.py @@ -6,6 +6,7 @@ from attrs import Factory, define, field from griptape.drivers import OpenAiImageGenerationDriver +from griptape.utils.decorators import lazy_property @define @@ -34,17 +35,16 @@ class AzureOpenAiImageGenerationDriver(OpenAiImageGenerationDriver): metadata={"serializable": False}, ) api_version: str = field(default="2024-02-01", kw_only=True, metadata={"serializable": True}) - client: openai.AzureOpenAI = field( - default=Factory( - lambda self: openai.AzureOpenAI( - organization=self.organization, - api_key=self.api_key, - api_version=self.api_version, - azure_endpoint=self.azure_endpoint, - azure_deployment=self.azure_deployment, - azure_ad_token=self.azure_ad_token, - azure_ad_token_provider=self.azure_ad_token_provider, - ), - takes_self=True, - ), - ) + _client: openai.AzureOpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.AzureOpenAI: + return openai.AzureOpenAI( + organization=self.organization, + api_key=self.api_key, + api_version=self.api_version, + azure_endpoint=self.azure_endpoint, + azure_deployment=self.azure_deployment, + azure_ad_token=self.azure_ad_token, + azure_ad_token_provider=self.azure_ad_token_provider, + ) diff --git a/griptape/drivers/image_generation/openai_image_generation_driver.py b/griptape/drivers/image_generation/openai_image_generation_driver.py index bf77ac300b..ec8129e892 100644 --- a/griptape/drivers/image_generation/openai_image_generation_driver.py +++ b/griptape/drivers/image_generation/openai_image_generation_driver.py @@ -4,10 +4,11 @@ from typing import TYPE_CHECKING, Literal, Optional, Union, cast import openai -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts import ImageArtifact from griptape.drivers import BaseImageGenerationDriver +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from openai.types.images_response import ImagesResponse @@ -38,12 +39,6 @@ class OpenAiImageGenerationDriver(BaseImageGenerationDriver): base_url: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) organization: Optional[str] = field(default=openai.organization, kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) style: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) quality: Union[Literal["standard"], Literal["hd"]] = field( default="standard", @@ -58,6 +53,11 @@ class OpenAiImageGenerationDriver(BaseImageGenerationDriver): Literal["1792x1024"], ] = field(default="1024x1024", kw_only=True, metadata={"serializable": True}) response_format: Literal["b64_json"] = field(default="b64_json", kw_only=True, metadata={"serializable": True}) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization) def try_text_to_image(self, prompts: list[str], negative_prompts: Optional[list[str]] = None) -> ImageArtifact: prompt = ", ".join(prompts) diff --git a/griptape/drivers/image_query/amazon_bedrock_image_query_driver.py b/griptape/drivers/image_query/amazon_bedrock_image_query_driver.py index 46406d9726..9742cb9c75 100644 --- a/griptape/drivers/image_query/amazon_bedrock_image_query_driver.py +++ b/griptape/drivers/image_query/amazon_bedrock_image_query_driver.py @@ -1,15 +1,17 @@ from __future__ import annotations import json -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING from attrs import Factory, define, field from griptape.drivers import BaseMultiModelImageQueryDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_bedrock import BedrockClient from griptape.artifacts import ImageArtifact, TextArtifact @@ -17,15 +19,16 @@ @define class AmazonBedrockImageQueryDriver(BaseMultiModelImageQueryDriver): session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - bedrock_client: Any = field( - default=Factory(lambda self: self.session.client("bedrock-runtime"), takes_self=True), - kw_only=True, - ) + _client: BedrockClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> BedrockClient: + return self.session.client("bedrock-runtime") def try_query(self, query: str, images: list[ImageArtifact]) -> TextArtifact: payload = self.image_query_model_driver.image_query_request_parameters(query, images, self.max_tokens) - response = self.bedrock_client.invoke_model( + response = self.client.invoke_model( modelId=self.model, contentType="application/json", accept="application/json", diff --git a/griptape/drivers/image_query/anthropic_image_query_driver.py b/griptape/drivers/image_query/anthropic_image_query_driver.py index a50685724f..191d953730 100644 --- a/griptape/drivers/image_query/anthropic_image_query_driver.py +++ b/griptape/drivers/image_query/anthropic_image_query_driver.py @@ -1,12 +1,16 @@ from __future__ import annotations -from typing import Any, Optional +from typing import TYPE_CHECKING, Optional -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts import ImageArtifact, TextArtifact from griptape.drivers import BaseImageQueryDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property + +if TYPE_CHECKING: + from anthropic import Anthropic @define @@ -21,13 +25,11 @@ class AnthropicImageQueryDriver(BaseImageQueryDriver): api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) model: str = field(kw_only=True, metadata={"serializable": True}) - client: Any = field( - default=Factory( - lambda self: import_optional_dependency("anthropic").Anthropic(api_key=self.api_key), - takes_self=True, - ), - kw_only=True, - ) + _client: Anthropic = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Anthropic: + return import_optional_dependency("anthropic").Anthropic(api_key=self.api_key) def try_query(self, query: str, images: list[ImageArtifact]) -> TextArtifact: if self.max_tokens is None: diff --git a/griptape/drivers/image_query/azure_openai_image_query_driver.py b/griptape/drivers/image_query/azure_openai_image_query_driver.py index 04492e4719..637fa11cc2 100644 --- a/griptape/drivers/image_query/azure_openai_image_query_driver.py +++ b/griptape/drivers/image_query/azure_openai_image_query_driver.py @@ -6,6 +6,7 @@ from attrs import Factory, define, field from griptape.drivers.image_query.openai_image_query_driver import OpenAiImageQueryDriver +from griptape.utils.decorators import lazy_property @define @@ -34,17 +35,16 @@ class AzureOpenAiImageQueryDriver(OpenAiImageQueryDriver): metadata={"serializable": False}, ) api_version: str = field(default="2024-02-01", kw_only=True, metadata={"serializable": True}) - client: openai.AzureOpenAI = field( - default=Factory( - lambda self: openai.AzureOpenAI( - organization=self.organization, - api_key=self.api_key, - api_version=self.api_version, - azure_endpoint=self.azure_endpoint, - azure_deployment=self.azure_deployment, - azure_ad_token=self.azure_ad_token, - azure_ad_token_provider=self.azure_ad_token_provider, - ), - takes_self=True, - ), - ) + _client: openai.AzureOpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.AzureOpenAI: + return openai.AzureOpenAI( + organization=self.organization, + api_key=self.api_key, + api_version=self.api_version, + azure_endpoint=self.azure_endpoint, + azure_deployment=self.azure_deployment, + azure_ad_token=self.azure_ad_token, + azure_ad_token_provider=self.azure_ad_token_provider, + ) diff --git a/griptape/drivers/image_query/openai_image_query_driver.py b/griptape/drivers/image_query/openai_image_query_driver.py index 6399efa95d..f0ef9e148f 100644 --- a/griptape/drivers/image_query/openai_image_query_driver.py +++ b/griptape/drivers/image_query/openai_image_query_driver.py @@ -3,7 +3,7 @@ from typing import Literal, Optional import openai -from attrs import Factory, define, field +from attrs import define, field from openai.types.chat import ( ChatCompletionContentPartImageParam, ChatCompletionContentPartParam, @@ -13,6 +13,7 @@ from griptape.artifacts import ImageArtifact, TextArtifact from griptape.drivers.image_query.base_image_query_driver import BaseImageQueryDriver +from griptape.utils.decorators import lazy_property @define @@ -24,12 +25,11 @@ class OpenAiImageQueryDriver(BaseImageQueryDriver): api_key: Optional[str] = field(default=None, kw_only=True) organization: Optional[str] = field(default=openai.organization, kw_only=True, metadata={"serializable": True}) image_quality: Literal["auto", "low", "high"] = field(default="auto", kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization) def try_query(self, query: str, images: list[ImageArtifact]) -> TextArtifact: message_parts: list[ChatCompletionContentPartParam] = [ diff --git a/griptape/drivers/memory/conversation/amazon_dynamodb_conversation_memory_driver.py b/griptape/drivers/memory/conversation/amazon_dynamodb_conversation_memory_driver.py index 0842870eb3..47ea13e0af 100644 --- a/griptape/drivers/memory/conversation/amazon_dynamodb_conversation_memory_driver.py +++ b/griptape/drivers/memory/conversation/amazon_dynamodb_conversation_memory_driver.py @@ -7,9 +7,11 @@ from griptape.drivers import BaseConversationMemoryDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_dynamodb.service_resource import Table from griptape.memory.structure import Run @@ -23,11 +25,11 @@ class AmazonDynamoDbConversationMemoryDriver(BaseConversationMemoryDriver): partition_key_value: str = field(kw_only=True, metadata={"serializable": True}) sort_key: Optional[str] = field(default=None, metadata={"serializable": True}) sort_key_value: Optional[str | int] = field(default=None, metadata={"serializable": True}) + _table: Table = field(default=None, kw_only=True, alias="table", metadata={"serializable": False}) - table: Any = field(init=False) - - def __attrs_post_init__(self) -> None: - self.table = self.session.resource("dynamodb").Table(self.table_name) + @lazy_property() + def table(self) -> Table: + return self.session.resource("dynamodb").Table(self.table_name) def store(self, runs: list[Run], metadata: dict) -> None: self.table.update_item( diff --git a/griptape/drivers/prompt/amazon_bedrock_prompt_driver.py b/griptape/drivers/prompt/amazon_bedrock_prompt_driver.py index bc339f6184..be34d2a8cf 100644 --- a/griptape/drivers/prompt/amazon_bedrock_prompt_driver.py +++ b/griptape/drivers/prompt/amazon_bedrock_prompt_driver.py @@ -31,6 +31,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import AmazonBedrockTokenizer, BaseTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -44,10 +45,6 @@ @define class AmazonBedrockPromptDriver(BasePromptDriver): session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - bedrock_client: Any = field( - default=Factory(lambda self: self.session.client("bedrock-runtime"), takes_self=True), - kw_only=True, - ) additional_model_request_fields: dict = field(default=Factory(dict), kw_only=True) tokenizer: BaseTokenizer = field( default=Factory(lambda self: AmazonBedrockTokenizer(model=self.model), takes_self=True), @@ -55,10 +52,15 @@ class AmazonBedrockPromptDriver(BasePromptDriver): ) use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) tool_choice: dict = field(default=Factory(lambda: {"auto": {}}), kw_only=True, metadata={"serializable": True}) + _client: Any = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Any: + return self.session.client("bedrock-runtime") @observable def try_run(self, prompt_stack: PromptStack) -> Message: - response = self.bedrock_client.converse(**self._base_params(prompt_stack)) + response = self.client.converse(**self._base_params(prompt_stack)) usage = response["usage"] output_message = response["output"]["message"] @@ -71,7 +73,7 @@ def try_run(self, prompt_stack: PromptStack) -> Message: @observable def try_stream(self, prompt_stack: PromptStack) -> Iterator[DeltaMessage]: - response = self.bedrock_client.converse_stream(**self._base_params(prompt_stack)) + response = self.client.converse_stream(**self._base_params(prompt_stack)) stream = response.get("stream") if stream is not None: diff --git a/griptape/drivers/prompt/amazon_sagemaker_jumpstart_prompt_driver.py b/griptape/drivers/prompt/amazon_sagemaker_jumpstart_prompt_driver.py index d7a2f5b0b2..2dcf55307c 100644 --- a/griptape/drivers/prompt/amazon_sagemaker_jumpstart_prompt_driver.py +++ b/griptape/drivers/prompt/amazon_sagemaker_jumpstart_prompt_driver.py @@ -10,6 +10,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import HuggingFaceTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -22,10 +23,6 @@ @define class AmazonSageMakerJumpstartPromptDriver(BasePromptDriver): session: boto3.Session = field(default=Factory(lambda: import_optional_dependency("boto3").Session()), kw_only=True) - sagemaker_client: Any = field( - default=Factory(lambda self: self.session.client("sagemaker-runtime"), takes_self=True), - kw_only=True, - ) endpoint: str = field(kw_only=True, metadata={"serializable": True}) custom_attributes: str = field(default="accept_eula=true", kw_only=True, metadata={"serializable": True}) inference_component_name: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) @@ -38,6 +35,11 @@ class AmazonSageMakerJumpstartPromptDriver(BasePromptDriver): ), kw_only=True, ) + _client: Any = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Any: + return self.session.client("sagemaker-runtime") @stream.validator # pyright: ignore[reportAttributeAccessIssue] def validate_stream(self, _: Attribute, stream: bool) -> None: # noqa: FBT001 @@ -51,7 +53,7 @@ def try_run(self, prompt_stack: PromptStack) -> Message: "parameters": {**self._base_params(prompt_stack)}, } - response = self.sagemaker_client.invoke_endpoint( + response = self.client.invoke_endpoint( EndpointName=self.endpoint, ContentType="application/json", Body=json.dumps(payload), diff --git a/griptape/drivers/prompt/anthropic_prompt_driver.py b/griptape/drivers/prompt/anthropic_prompt_driver.py index ae50bc59e5..8c944b2cce 100644 --- a/griptape/drivers/prompt/anthropic_prompt_driver.py +++ b/griptape/drivers/prompt/anthropic_prompt_driver.py @@ -32,6 +32,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import AnthropicTokenizer, BaseTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -54,13 +55,6 @@ class AnthropicPromptDriver(BasePromptDriver): api_key: Optional[str] = field(kw_only=True, default=None, metadata={"serializable": False}) model: str = field(kw_only=True, metadata={"serializable": True}) - client: Client = field( - default=Factory( - lambda self: import_optional_dependency("anthropic").Anthropic(api_key=self.api_key), - takes_self=True, - ), - kw_only=True, - ) tokenizer: BaseTokenizer = field( default=Factory(lambda self: AnthropicTokenizer(model=self.model), takes_self=True), kw_only=True, @@ -70,6 +64,11 @@ class AnthropicPromptDriver(BasePromptDriver): tool_choice: dict = field(default=Factory(lambda: {"type": "auto"}), kw_only=True, metadata={"serializable": False}) use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) max_tokens: int = field(default=1000, kw_only=True, metadata={"serializable": True}) + _client: Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Client: + return import_optional_dependency("anthropic").Anthropic(api_key=self.api_key) @observable def try_run(self, prompt_stack: PromptStack) -> Message: diff --git a/griptape/drivers/prompt/azure_openai_chat_prompt_driver.py b/griptape/drivers/prompt/azure_openai_chat_prompt_driver.py index b08b51b69c..5bb7e07603 100644 --- a/griptape/drivers/prompt/azure_openai_chat_prompt_driver.py +++ b/griptape/drivers/prompt/azure_openai_chat_prompt_driver.py @@ -6,6 +6,7 @@ from attrs import Factory, define, field from griptape.drivers import OpenAiChatPromptDriver +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from griptape.common import PromptStack @@ -37,20 +38,19 @@ class AzureOpenAiChatPromptDriver(OpenAiChatPromptDriver): metadata={"serializable": False}, ) api_version: str = field(default="2023-05-15", kw_only=True, metadata={"serializable": True}) - client: openai.AzureOpenAI = field( - default=Factory( - lambda self: openai.AzureOpenAI( - organization=self.organization, - api_key=self.api_key, - api_version=self.api_version, - azure_endpoint=self.azure_endpoint, - azure_deployment=self.azure_deployment, - azure_ad_token=self.azure_ad_token, - azure_ad_token_provider=self.azure_ad_token_provider, - ), - takes_self=True, - ), - ) + _client: openai.AzureOpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.AzureOpenAI: + return openai.AzureOpenAI( + organization=self.organization, + api_key=self.api_key, + api_version=self.api_version, + azure_endpoint=self.azure_endpoint, + azure_deployment=self.azure_deployment, + azure_ad_token=self.azure_ad_token, + azure_ad_token_provider=self.azure_ad_token_provider, + ) def _base_params(self, prompt_stack: PromptStack) -> dict: params = super()._base_params(prompt_stack) diff --git a/griptape/drivers/prompt/cohere_prompt_driver.py b/griptape/drivers/prompt/cohere_prompt_driver.py index ff1a8b4824..b31c78ea35 100644 --- a/griptape/drivers/prompt/cohere_prompt_driver.py +++ b/griptape/drivers/prompt/cohere_prompt_driver.py @@ -23,6 +23,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import BaseTokenizer, CohereTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -45,14 +46,16 @@ class CoherePromptDriver(BasePromptDriver): api_key: str = field(metadata={"serializable": False}) model: str = field(metadata={"serializable": True}) - client: Client = field( - default=Factory(lambda self: import_optional_dependency("cohere").Client(self.api_key), takes_self=True), - ) + force_single_step: bool = field(default=False, kw_only=True, metadata={"serializable": True}) + use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) + _client: Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) tokenizer: BaseTokenizer = field( default=Factory(lambda self: CohereTokenizer(model=self.model, client=self.client), takes_self=True), ) - force_single_step: bool = field(default=False, kw_only=True, metadata={"serializable": True}) - use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) + + @lazy_property() + def client(self) -> Client: + return import_optional_dependency("cohere").Client(self.api_key) @observable def try_run(self, prompt_stack: PromptStack) -> Message: diff --git a/griptape/drivers/prompt/google_prompt_driver.py b/griptape/drivers/prompt/google_prompt_driver.py index 6b18f60416..4afdad5c6c 100644 --- a/griptape/drivers/prompt/google_prompt_driver.py +++ b/griptape/drivers/prompt/google_prompt_driver.py @@ -26,6 +26,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import BaseTokenizer, GoogleTokenizer from griptape.utils import import_optional_dependency, remove_key_in_dict_recursively +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -44,17 +45,13 @@ class GooglePromptDriver(BasePromptDriver): Attributes: api_key: Google API key. model: Google model name. - model_client: Custom `GenerativeModel` client. + client: Custom `GenerativeModel` client. top_p: Optional value for top_p. top_k: Optional value for top_k. """ api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) model: str = field(kw_only=True, metadata={"serializable": True}) - model_client: GenerativeModel = field( - default=Factory(lambda self: self._default_model_client(), takes_self=True), - kw_only=True, - ) tokenizer: BaseTokenizer = field( default=Factory(lambda self: GoogleTokenizer(api_key=self.api_key, model=self.model), takes_self=True), kw_only=True, @@ -63,11 +60,19 @@ class GooglePromptDriver(BasePromptDriver): top_k: Optional[int] = field(default=None, kw_only=True, metadata={"serializable": True}) use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) tool_choice: str = field(default="auto", kw_only=True, metadata={"serializable": True}) + _client: GenerativeModel = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> GenerativeModel: + genai = import_optional_dependency("google.generativeai") + genai.configure(api_key=self.api_key) + + return genai.GenerativeModel(self.model) @observable def try_run(self, prompt_stack: PromptStack) -> Message: messages = self.__to_google_messages(prompt_stack) - response: GenerateContentResponse = self.model_client.generate_content( + response: GenerateContentResponse = self.client.generate_content( messages, **self._base_params(prompt_stack), ) @@ -86,7 +91,7 @@ def try_run(self, prompt_stack: PromptStack) -> Message: @observable def try_stream(self, prompt_stack: PromptStack) -> Iterator[DeltaMessage]: messages = self.__to_google_messages(prompt_stack) - response: GenerateContentResponse = self.model_client.generate_content( + response: GenerateContentResponse = self.client.generate_content( messages, **self._base_params(prompt_stack), stream=True, @@ -119,7 +124,7 @@ def _base_params(self, prompt_stack: PromptStack) -> dict: system_messages = prompt_stack.system_messages if system_messages: - self.model_client._system_instruction = types.ContentDict( + self.client._system_instruction = types.ContentDict( role="system", parts=[protos.Part(text=system_message.to_text()) for system_message in system_messages], ) @@ -146,12 +151,6 @@ def _base_params(self, prompt_stack: PromptStack) -> dict: ), } - def _default_model_client(self) -> GenerativeModel: - genai = import_optional_dependency("google.generativeai") - genai.configure(api_key=self.api_key) - - return genai.GenerativeModel(self.model) - def __to_google_messages(self, prompt_stack: PromptStack) -> ContentsType: types = import_optional_dependency("google.generativeai.types") diff --git a/griptape/drivers/prompt/huggingface_hub_prompt_driver.py b/griptape/drivers/prompt/huggingface_hub_prompt_driver.py index 657b5747c8..68267f755b 100644 --- a/griptape/drivers/prompt/huggingface_hub_prompt_driver.py +++ b/griptape/drivers/prompt/huggingface_hub_prompt_driver.py @@ -8,6 +8,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import HuggingFaceTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -32,16 +33,6 @@ class HuggingFaceHubPromptDriver(BasePromptDriver): max_tokens: int = field(default=250, kw_only=True, metadata={"serializable": True}) params: dict = field(factory=dict, kw_only=True, metadata={"serializable": True}) model: str = field(kw_only=True, metadata={"serializable": True}) - client: InferenceClient = field( - default=Factory( - lambda self: import_optional_dependency("huggingface_hub").InferenceClient( - model=self.model, - token=self.api_token, - ), - takes_self=True, - ), - kw_only=True, - ) tokenizer: HuggingFaceTokenizer = field( default=Factory( lambda self: HuggingFaceTokenizer(model=self.model, max_output_tokens=self.max_tokens), @@ -49,6 +40,14 @@ class HuggingFaceHubPromptDriver(BasePromptDriver): ), kw_only=True, ) + _client: InferenceClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> InferenceClient: + return import_optional_dependency("huggingface_hub").InferenceClient( + model=self.model, + token=self.api_token, + ) @observable def try_run(self, prompt_stack: PromptStack) -> Message: diff --git a/griptape/drivers/prompt/huggingface_pipeline_prompt_driver.py b/griptape/drivers/prompt/huggingface_pipeline_prompt_driver.py index 128167f527..1978b339aa 100644 --- a/griptape/drivers/prompt/huggingface_pipeline_prompt_driver.py +++ b/griptape/drivers/prompt/huggingface_pipeline_prompt_driver.py @@ -9,6 +9,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import HuggingFaceTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -35,23 +36,24 @@ class HuggingFacePipelinePromptDriver(BasePromptDriver): ), kw_only=True, ) - pipe: TextGenerationPipeline = field( - default=Factory( - lambda self: import_optional_dependency("transformers").pipeline( - "text-generation", - model=self.model, - max_new_tokens=self.max_tokens, - tokenizer=self.tokenizer.tokenizer, - ), - takes_self=True, - ), + _pipeline: TextGenerationPipeline = field( + default=None, kw_only=True, alias="pipeline", metadata={"serializable": False} ) + @lazy_property() + def pipeline(self) -> TextGenerationPipeline: + return import_optional_dependency("transformers").pipeline( + task="text-generation", + model=self.model, + max_new_tokens=self.max_tokens, + tokenizer=self.tokenizer.tokenizer, + ) + @observable def try_run(self, prompt_stack: PromptStack) -> Message: messages = self._prompt_stack_to_messages(prompt_stack) - result = self.pipe( + result = self.pipeline( messages, max_new_tokens=self.max_tokens, temperature=self.temperature, diff --git a/griptape/drivers/prompt/ollama_prompt_driver.py b/griptape/drivers/prompt/ollama_prompt_driver.py index 70d4ce89af..5f9e32e2f6 100644 --- a/griptape/drivers/prompt/ollama_prompt_driver.py +++ b/griptape/drivers/prompt/ollama_prompt_driver.py @@ -22,6 +22,7 @@ from griptape.drivers import BasePromptDriver from griptape.tokenizers import SimpleTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from ollama import Client @@ -40,10 +41,6 @@ class OllamaPromptDriver(BasePromptDriver): model: str = field(kw_only=True, metadata={"serializable": True}) host: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - client: Client = field( - default=Factory(lambda self: import_optional_dependency("ollama").Client(host=self.host), takes_self=True), - kw_only=True, - ) tokenizer: BaseTokenizer = field( default=Factory( lambda self: SimpleTokenizer( @@ -67,6 +64,11 @@ class OllamaPromptDriver(BasePromptDriver): kw_only=True, ) use_native_tools: bool = field(default=True, kw_only=True, metadata={"serializable": True}) + _client: Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Client: + return import_optional_dependency("ollama").Client(host=self.host) @observable def try_run(self, prompt_stack: PromptStack) -> Message: diff --git a/griptape/drivers/prompt/openai_chat_prompt_driver.py b/griptape/drivers/prompt/openai_chat_prompt_driver.py index 987bdc2add..bab20d3f07 100644 --- a/griptape/drivers/prompt/openai_chat_prompt_driver.py +++ b/griptape/drivers/prompt/openai_chat_prompt_driver.py @@ -25,6 +25,7 @@ ) from griptape.drivers import BasePromptDriver from griptape.tokenizers import BaseTokenizer, OpenAiTokenizer +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from collections.abc import Iterator @@ -55,12 +56,6 @@ class OpenAiChatPromptDriver(BasePromptDriver): base_url: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) organization: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) model: str = field(kw_only=True, metadata={"serializable": True}) tokenizer: BaseTokenizer = field( default=Factory(lambda self: OpenAiTokenizer(model=self.model), takes_self=True), @@ -88,6 +83,15 @@ class OpenAiChatPromptDriver(BasePromptDriver): ), kw_only=True, ) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI( + base_url=self.base_url, + api_key=self.api_key, + organization=self.organization, + ) @observable def try_run(self, prompt_stack: PromptStack) -> Message: diff --git a/griptape/drivers/sql/amazon_redshift_sql_driver.py b/griptape/drivers/sql/amazon_redshift_sql_driver.py index 837405e832..8e5d912c89 100644 --- a/griptape/drivers/sql/amazon_redshift_sql_driver.py +++ b/griptape/drivers/sql/amazon_redshift_sql_driver.py @@ -3,12 +3,14 @@ import time from typing import TYPE_CHECKING, Any, Optional -from attrs import Attribute, Factory, define, field +from attrs import Attribute, define, field from griptape.drivers import BaseSqlDriver +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import boto3 + from mypy_boto3_redshift_data import RedshiftDataAPIServiceClient @define @@ -20,11 +22,14 @@ class AmazonRedshiftSqlDriver(BaseSqlDriver): db_user: Optional[str] = field(default=None, kw_only=True) database_credentials_secret_arn: Optional[str] = field(default=None, kw_only=True) wait_for_query_completion_sec: float = field(default=0.3, kw_only=True) - client: Any = field( - default=Factory(lambda self: self.session.client("redshift-data"), takes_self=True), - kw_only=True, + _client: RedshiftDataAPIServiceClient = field( + default=None, kw_only=True, alias="client", metadata={"serializable": False} ) + @lazy_property() + def client(self) -> RedshiftDataAPIServiceClient: + return self.session.client("redshift-data") + @workgroup_name.validator # pyright: ignore[reportAttributeAccessIssue] def validate_params(self, _: Attribute, workgroup_name: Optional[str]) -> None: if not self.cluster_identifier and not self.workgroup_name: diff --git a/griptape/drivers/sql/snowflake_sql_driver.py b/griptape/drivers/sql/snowflake_sql_driver.py index 656bc4b994..d1b4310b5a 100644 --- a/griptape/drivers/sql/snowflake_sql_driver.py +++ b/griptape/drivers/sql/snowflake_sql_driver.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING, Any, Callable, Optional -from attrs import Attribute, Factory, define, field +from attrs import Attribute, define, field from griptape.drivers import BaseSqlDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from snowflake.connector import SnowflakeConnection @@ -15,18 +16,7 @@ @define class SnowflakeSqlDriver(BaseSqlDriver): connection_func: Callable[[], SnowflakeConnection] = field(kw_only=True) - engine: Engine = field( - default=Factory( - # Creator bypasses the URL param - # https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.create_engine.params.creator - lambda self: import_optional_dependency("sqlalchemy").create_engine( - "snowflake://not@used/db", - creator=self.connection_func, - ), - takes_self=True, - ), - kw_only=True, - ) + _engine: Engine = field(default=None, kw_only=True, alias="engine", metadata={"serializable": False}) @connection_func.validator # pyright: ignore[reportFunctionMemberAccess] def validate_connection_func(self, _: Attribute, connection_func: Callable[[], SnowflakeConnection]) -> None: @@ -38,10 +28,12 @@ def validate_connection_func(self, _: Attribute, connection_func: Callable[[], S if not snowflake_connection.schema or not snowflake_connection.database: raise ValueError("Provide a schema and database for the Snowflake connection") - @engine.validator # pyright: ignore[reportAttributeAccessIssue] - def validate_engine_url(self, _: Attribute, engine: Engine) -> None: - if not engine.url.render_as_string().startswith("snowflake://"): - raise ValueError("Provide a Snowflake connection") + @lazy_property() + def engine(self) -> Engine: + return import_optional_dependency("sqlalchemy").create_engine( + "snowflake://not@used/db", + creator=self.connection_func, + ) def execute_query(self, query: str) -> Optional[list[BaseSqlDriver.RowResult]]: rows = self.execute_query_raw(query) diff --git a/griptape/drivers/sql/sql_driver.py b/griptape/drivers/sql/sql_driver.py index d2293f94d3..cb7a673417 100644 --- a/griptape/drivers/sql/sql_driver.py +++ b/griptape/drivers/sql/sql_driver.py @@ -6,6 +6,7 @@ from griptape.drivers import BaseSqlDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from sqlalchemy.engine import Engine @@ -15,12 +16,11 @@ class SqlDriver(BaseSqlDriver): engine_url: str = field(kw_only=True) create_engine_params: dict = field(factory=dict, kw_only=True) - engine: Engine = field(init=False) + _engine: Engine = field(default=None, kw_only=True, alias="engine", metadata={"serializable": False}) - def __attrs_post_init__(self) -> None: - sqlalchemy = import_optional_dependency("sqlalchemy") - - self.engine = sqlalchemy.create_engine(self.engine_url, **self.create_engine_params) + @lazy_property() + def engine(self) -> Engine: + return import_optional_dependency("sqlalchemy").create_engine(self.engine_url, **self.create_engine_params) def execute_query(self, query: str) -> Optional[list[BaseSqlDriver.RowResult]]: rows = self.execute_query_raw(query) diff --git a/griptape/drivers/text_to_speech/azure_openai_text_to_speech_driver.py b/griptape/drivers/text_to_speech/azure_openai_text_to_speech_driver.py index 562a1d6376..f64ab0e2db 100644 --- a/griptape/drivers/text_to_speech/azure_openai_text_to_speech_driver.py +++ b/griptape/drivers/text_to_speech/azure_openai_text_to_speech_driver.py @@ -6,6 +6,7 @@ from attrs import Factory, define, field from griptape.drivers import OpenAiTextToSpeechDriver +from griptape.utils.decorators import lazy_property @define @@ -35,17 +36,16 @@ class AzureOpenAiTextToSpeechDriver(OpenAiTextToSpeechDriver): metadata={"serializable": False}, ) api_version: str = field(default="2024-07-01-preview", kw_only=True, metadata={"serializable": True}) - client: openai.AzureOpenAI = field( - default=Factory( - lambda self: openai.AzureOpenAI( - organization=self.organization, - api_key=self.api_key, - api_version=self.api_version, - azure_endpoint=self.azure_endpoint, - azure_deployment=self.azure_deployment, - azure_ad_token=self.azure_ad_token, - azure_ad_token_provider=self.azure_ad_token_provider, - ), - takes_self=True, - ), - ) + _client: openai.AzureOpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.AzureOpenAI: + return openai.AzureOpenAI( + organization=self.organization, + api_key=self.api_key, + api_version=self.api_version, + azure_endpoint=self.azure_endpoint, + azure_deployment=self.azure_deployment, + azure_ad_token=self.azure_ad_token, + azure_ad_token_provider=self.azure_ad_token_provider, + ) diff --git a/griptape/drivers/text_to_speech/elevenlabs_text_to_speech_driver.py b/griptape/drivers/text_to_speech/elevenlabs_text_to_speech_driver.py index f4be581621..ef6352cea6 100644 --- a/griptape/drivers/text_to_speech/elevenlabs_text_to_speech_driver.py +++ b/griptape/drivers/text_to_speech/elevenlabs_text_to_speech_driver.py @@ -1,27 +1,28 @@ from __future__ import annotations -from typing import Any +from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts.audio_artifact import AudioArtifact from griptape.drivers import BaseTextToSpeechDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property + +if TYPE_CHECKING: + from elevenlabs.client import ElevenLabs @define class ElevenLabsTextToSpeechDriver(BaseTextToSpeechDriver): api_key: str = field(kw_only=True, metadata={"serializable": True}) - client: Any = field( - default=Factory( - lambda self: import_optional_dependency("elevenlabs.client").ElevenLabs(api_key=self.api_key), - takes_self=True, - ), - kw_only=True, - metadata={"serializable": True}, - ) voice: str = field(kw_only=True, metadata={"serializable": True}) output_format: str = field(default="mp3_44100_128", kw_only=True, metadata={"serializable": True}) + _client: ElevenLabs = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> ElevenLabs: + return import_optional_dependency("elevenlabs.client").ElevenLabs(api_key=self.api_key) def try_text_to_audio(self, prompts: list[str]) -> AudioArtifact: audio = self.client.generate( diff --git a/griptape/drivers/text_to_speech/openai_text_to_speech_driver.py b/griptape/drivers/text_to_speech/openai_text_to_speech_driver.py index 543ef1ec79..558e2f875b 100644 --- a/griptape/drivers/text_to_speech/openai_text_to_speech_driver.py +++ b/griptape/drivers/text_to_speech/openai_text_to_speech_driver.py @@ -3,10 +3,11 @@ from typing import Literal, Optional import openai -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts.audio_artifact import AudioArtifact from griptape.drivers import BaseTextToSpeechDriver +from griptape.utils.decorators import lazy_property @define @@ -23,12 +24,15 @@ class OpenAiTextToSpeechDriver(BaseTextToSpeechDriver): base_url: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) api_key: Optional[str] = field(default=None, kw_only=True) organization: Optional[str] = field(default=openai.organization, kw_only=True, metadata={"serializable": True}) - client: openai.OpenAI = field( - default=Factory( - lambda self: openai.OpenAI(api_key=self.api_key, base_url=self.base_url, organization=self.organization), - takes_self=True, - ), - ) + _client: openai.OpenAI = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> openai.OpenAI: + return openai.OpenAI( + api_key=self.api_key, + base_url=self.base_url, + organization=self.organization, + ) def try_text_to_audio(self, prompts: list[str]) -> AudioArtifact: response = self.client.audio.speech.create( diff --git a/griptape/drivers/vector/amazon_opensearch_vector_store_driver.py b/griptape/drivers/vector/amazon_opensearch_vector_store_driver.py index b1d8819587..465dfa4764 100644 --- a/griptape/drivers/vector/amazon_opensearch_vector_store_driver.py +++ b/griptape/drivers/vector/amazon_opensearch_vector_store_driver.py @@ -9,7 +9,6 @@ if TYPE_CHECKING: from boto3 import Session - from opensearchpy import OpenSearch @define @@ -36,19 +35,6 @@ class AmazonOpenSearchVectorStoreDriver(OpenSearchVectorStoreDriver): ), ) - client: OpenSearch = field( - default=Factory( - lambda self: import_optional_dependency("opensearchpy").OpenSearch( - hosts=[{"host": self.host, "port": self.port}], - http_auth=self.http_auth, - use_ssl=self.use_ssl, - verify_certs=self.verify_certs, - connection_class=import_optional_dependency("opensearchpy").RequestsHttpConnection, - ), - takes_self=True, - ), - ) - def upsert_vector( self, vector: list[float], diff --git a/griptape/drivers/vector/astradb_vector_store_driver.py b/griptape/drivers/vector/astradb_vector_store_driver.py index 029fa382d9..1e83988090 100644 --- a/griptape/drivers/vector/astradb_vector_store_driver.py +++ b/griptape/drivers/vector/astradb_vector_store_driver.py @@ -6,10 +6,11 @@ from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: - from astrapy import Collection - from astrapy.authentication import TokenProvider + import astrapy + import astrapy.authentication @define @@ -26,33 +27,37 @@ class AstraDbVectorStoreDriver(BaseVectorStoreDriver): It can be omitted for production Astra DB targets. See `astrapy.constants.Environment` for allowed values. astra_db_namespace: optional specification of the namespace (in the Astra database) for the data. *Note*: not to be confused with the "namespace" mentioned elsewhere, which is a grouping within this vector store. + caller_name: the name of the caller for the Astra DB client. Defaults to "griptape". + client: an instance of `astrapy.DataAPIClient` for the Astra DB. + collection: an instance of `astrapy.Collection` for the Astra DB. """ api_endpoint: str = field(kw_only=True, metadata={"serializable": True}) - token: Optional[str | TokenProvider] = field(kw_only=True, default=None, metadata={"serializable": False}) + token: Optional[str | astrapy.authentication.TokenProvider] = field( + kw_only=True, default=None, metadata={"serializable": False} + ) collection_name: str = field(kw_only=True, metadata={"serializable": True}) environment: Optional[str] = field(kw_only=True, default=None, metadata={"serializable": True}) astra_db_namespace: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - - collection: Collection = field(init=False) - - def __attrs_post_init__(self) -> None: - astrapy = import_optional_dependency("astrapy") - self.collection = ( - astrapy.DataAPIClient( - caller_name="griptape", - environment=self.environment, - ) - .get_database( - self.api_endpoint, - token=self.token, - namespace=self.astra_db_namespace, - ) - .get_collection( - name=self.collection_name, - ) + caller_name: str = field(default="griptape", kw_only=True, metadata={"serializable": False}) + _client: astrapy.DataAPIClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + _collection: astrapy.Collection = field( + default=None, kw_only=True, alias="collection", metadata={"serializable": False} + ) + + @lazy_property() + def client(self) -> astrapy.DataAPIClient: + return import_optional_dependency("astrapy").DataAPIClient( + caller_name=self.caller_name, + environment=self.environment, ) + @lazy_property() + def collection(self) -> astrapy.Collection: + return self.client.get_database( + self.api_endpoint, token=self.token, namespace=self.astra_db_namespace + ).get_collection(self.collection_name) + def delete_vector(self, vector_id: str) -> None: """Delete a vector from Astra DB store. diff --git a/griptape/drivers/vector/marqo_vector_store_driver.py b/griptape/drivers/vector/marqo_vector_store_driver.py index caab118b87..55c3692a1f 100644 --- a/griptape/drivers/vector/marqo_vector_store_driver.py +++ b/griptape/drivers/vector/marqo_vector_store_driver.py @@ -2,11 +2,12 @@ from typing import TYPE_CHECKING, Any, NoReturn, Optional -from attrs import Factory, define, field +from attrs import define, field from griptape import utils from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import marqo @@ -21,20 +22,18 @@ class MarqoVectorStoreDriver(BaseVectorStoreDriver): Attributes: api_key: The API key for the Marqo API. url: The URL to the Marqo API. - mq: An optional Marqo client. Defaults to a new client with the given URL and API key. + client: An optional Marqo client. Defaults to a new client with the given URL and API key. index: The name of the index to use. """ api_key: str = field(kw_only=True, metadata={"serializable": True}) url: str = field(kw_only=True, metadata={"serializable": True}) - mq: Optional[marqo.Client] = field( - default=Factory( - lambda self: import_optional_dependency("marqo").Client(self.url, api_key=self.api_key), - takes_self=True, - ), - kw_only=True, - ) index: str = field(kw_only=True, metadata={"serializable": True}) + _client: marqo.Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> marqo.Client: + return import_optional_dependency("marqo").Client(self.url, api_key=self.api_key) def upsert_text( self, @@ -65,7 +64,7 @@ def upsert_text( if namespace: doc["namespace"] = namespace - response = self.mq.index(self.index).add_documents([doc], tensor_fields=["Description"]) + response = self.client.index(self.index).add_documents([doc], tensor_fields=["Description"]) if isinstance(response, dict) and "items" in response and response["items"]: return response["items"][0]["_id"] else: @@ -102,7 +101,7 @@ def upsert_text_artifact( "namespace": namespace, } - response = self.mq.index(self.index).add_documents([doc], tensor_fields=["Description", "artifact"]) + response = self.client.index(self.index).add_documents([doc], tensor_fields=["Description", "artifact"]) if isinstance(response, dict) and "items" in response and response["items"]: return response["items"][0]["_id"] else: @@ -118,7 +117,7 @@ def load_entry(self, vector_id: str, *, namespace: Optional[str] = None) -> Opti Returns: The loaded Entry if found, otherwise None. """ - result = self.mq.index(self.index).get_document(document_id=vector_id, expose_facets=True) + result = self.client.index(self.index).get_document(document_id=vector_id, expose_facets=True) if result and "_tensor_facets" in result and len(result["_tensor_facets"]) > 0: return BaseVectorStoreDriver.Entry( @@ -141,15 +140,15 @@ def load_entries(self, *, namespace: Optional[str] = None) -> list[BaseVectorSto filter_string = f"namespace:{namespace}" if namespace else None if filter_string is not None: - results = self.mq.index(self.index).search("", limit=10000, filter_string=filter_string) + results = self.client.index(self.index).search("", limit=10000, filter_string=filter_string) else: - results = self.mq.index(self.index).search("", limit=10000) + results = self.client.index(self.index).search("", limit=10000) # get all _id's from search results ids = [r["_id"] for r in results["hits"]] # get documents corresponding to the ids - documents = self.mq.index(self.index).get_documents(document_ids=ids, expose_facets=True) + documents = self.client.index(self.index).get_documents(document_ids=ids, expose_facets=True) # for each document, if it's found, create an Entry object entries = [] @@ -195,11 +194,12 @@ def query( "filter_string": f"namespace:{namespace}" if namespace else None, } | kwargs - results = self.mq.index(self.index).search(query, **params) + results = self.client.index(self.index).search(query, **params) if include_vectors: results["hits"] = [ - {**r, **self.mq.index(self.index).get_document(r["_id"], expose_facets=True)} for r in results["hits"] + {**r, **self.client.index(self.index).get_document(r["_id"], expose_facets=True)} + for r in results["hits"] ] return [ @@ -218,7 +218,7 @@ def delete_index(self, name: str) -> dict[str, Any]: Args: name: The name of the index to delete. """ - return self.mq.delete_index(name) + return self.client.delete_index(name) def get_indexes(self) -> list[str]: """Get a list of all indexes in the Marqo client. @@ -226,7 +226,7 @@ def get_indexes(self) -> list[str]: Returns: The list of all indexes. """ - return [index["index"] for index in self.mq.get_indexes()["results"]] + return [index["index"] for index in self.client.get_indexes()["results"]] def upsert_vector( self, diff --git a/griptape/drivers/vector/mongodb_atlas_vector_store_driver.py b/griptape/drivers/vector/mongodb_atlas_vector_store_driver.py index bc3f1e22f6..a6f32620a4 100644 --- a/griptape/drivers/vector/mongodb_atlas_vector_store_driver.py +++ b/griptape/drivers/vector/mongodb_atlas_vector_store_driver.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING, Optional -from attrs import Factory, define, field +from attrs import define, field from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from pymongo import MongoClient @@ -37,12 +38,11 @@ class MongoDbAtlasVectorStoreDriver(BaseVectorStoreDriver): kw_only=True, metadata={"serializable": True}, ) # https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-stage/#fields - client: MongoClient = field( - default=Factory( - lambda self: import_optional_dependency("pymongo").MongoClient(self.connection_string), - takes_self=True, - ), - ) + _client: MongoClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> MongoClient: + return import_optional_dependency("pymongo").MongoClient(self.connection_string) def get_collection(self) -> Collection: """Returns the MongoDB Collection instance for the specified database and collection name.""" diff --git a/griptape/drivers/vector/opensearch_vector_store_driver.py b/griptape/drivers/vector/opensearch_vector_store_driver.py index cf944116a1..5f247f6db3 100644 --- a/griptape/drivers/vector/opensearch_vector_store_driver.py +++ b/griptape/drivers/vector/opensearch_vector_store_driver.py @@ -3,11 +3,12 @@ import logging from typing import TYPE_CHECKING, NoReturn, Optional -from attrs import Factory, define, field +from attrs import define, field from griptape import utils from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from opensearchpy import OpenSearch @@ -32,19 +33,19 @@ class OpenSearchVectorStoreDriver(BaseVectorStoreDriver): use_ssl: bool = field(default=True, kw_only=True, metadata={"serializable": True}) verify_certs: bool = field(default=True, kw_only=True, metadata={"serializable": True}) index_name: str = field(kw_only=True, metadata={"serializable": True}) - - client: OpenSearch = field( - default=Factory( - lambda self: import_optional_dependency("opensearchpy").OpenSearch( - hosts=[{"host": self.host, "port": self.port}], - http_auth=self.http_auth, - use_ssl=self.use_ssl, - verify_certs=self.verify_certs, - connection_class=import_optional_dependency("opensearchpy").RequestsHttpConnection, - ), - takes_self=True, - ), - ) + _client: OpenSearch = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> OpenSearch: + opensearchpy = import_optional_dependency("opensearchpy") + + return opensearchpy.OpenSearch( + hosts=[{"host": self.host, "port": self.port}], + http_auth=self.http_auth, + use_ssl=self.use_ssl, + verify_certs=self.verify_certs, + connection_class=opensearchpy.RequestsHttpConnection, + ) def upsert_vector( self, diff --git a/griptape/drivers/vector/pgvector_vector_store_driver.py b/griptape/drivers/vector/pgvector_vector_store_driver.py index 30f437c7e4..c1a6bef06c 100644 --- a/griptape/drivers/vector/pgvector_vector_store_driver.py +++ b/griptape/drivers/vector/pgvector_vector_store_driver.py @@ -9,9 +9,10 @@ from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: - from sqlalchemy.engine import Engine + import sqlalchemy @define @@ -27,14 +28,14 @@ class PgVectorVectorStoreDriver(BaseVectorStoreDriver): connection_string: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) create_engine_params: dict = field(factory=dict, kw_only=True, metadata={"serializable": True}) - engine: Optional[Engine] = field(default=None, kw_only=True) table_name: str = field(kw_only=True, metadata={"serializable": True}) _model: Any = field(default=Factory(lambda self: self.default_vector_model(), takes_self=True)) + _engine: sqlalchemy.Engine = field(default=None, kw_only=True, alias="engine", metadata={"serializable": False}) @connection_string.validator # pyright: ignore[reportAttributeAccessIssue] def validate_connection_string(self, _: Attribute, connection_string: Optional[str]) -> None: # If an engine is provided, the connection string is not used. - if self.engine is not None: + if self._engine is not None: return # If an engine is not provided, a connection string is required. @@ -44,22 +45,11 @@ def validate_connection_string(self, _: Attribute, connection_string: Optional[s if not connection_string.startswith("postgresql://"): raise ValueError("The connection string must describe a Postgres database connection") - @engine.validator # pyright: ignore[reportAttributeAccessIssue] - def validate_engine(self, _: Attribute, engine: Optional[Engine]) -> None: - # If a connection string is provided, an engine does not need to be provided. - if self.connection_string is not None: - return - - # If a connection string is not provided, an engine is required. - if engine is None: - raise ValueError("An engine or connection string is required") - - def __attrs_post_init__(self) -> None: - if self.engine is None: - if self.connection_string is None: - raise ValueError("An engine or connection string is required") - sqlalchemy = import_optional_dependency("sqlalchemy") - self.engine = sqlalchemy.create_engine(self.connection_string, **self.create_engine_params) + @lazy_property() + def engine(self) -> sqlalchemy.Engine: + return import_optional_dependency("sqlalchemy").create_engine( + self.connection_string, **self.create_engine_params + ) def setup( self, diff --git a/griptape/drivers/vector/pinecone_vector_store_driver.py b/griptape/drivers/vector/pinecone_vector_store_driver.py index a3a132ab36..500b090f58 100644 --- a/griptape/drivers/vector/pinecone_vector_store_driver.py +++ b/griptape/drivers/vector/pinecone_vector_store_driver.py @@ -6,6 +6,7 @@ from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency, str_to_hash +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: import pinecone @@ -17,16 +18,20 @@ class PineconeVectorStoreDriver(BaseVectorStoreDriver): index_name: str = field(kw_only=True, metadata={"serializable": True}) environment: str = field(kw_only=True, metadata={"serializable": True}) project_name: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) - index: pinecone.Index = field(init=False) + _client: pinecone.Pinecone = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + _index: pinecone.Index = field(default=None, kw_only=True, alias="index", metadata={"serializable": False}) - def __attrs_post_init__(self) -> None: - pinecone = import_optional_dependency("pinecone").Pinecone( + @lazy_property() + def client(self) -> pinecone.Pinecone: + return import_optional_dependency("pinecone").Pinecone( api_key=self.api_key, environment=self.environment, project_name=self.project_name, ) - self.index = pinecone.Index(self.index_name) + @lazy_property() + def index(self) -> pinecone.Index: + return self.client.get_index(self.index_name) def upsert_vector( self, diff --git a/griptape/drivers/vector/qdrant_vector_store_driver.py b/griptape/drivers/vector/qdrant_vector_store_driver.py index 154e54af73..79cf64f375 100644 --- a/griptape/drivers/vector/qdrant_vector_store_driver.py +++ b/griptape/drivers/vector/qdrant_vector_store_driver.py @@ -2,12 +2,17 @@ import logging import uuid -from typing import Optional +from typing import TYPE_CHECKING, Optional from attrs import define, field from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property + +if TYPE_CHECKING: + from qdrant_client import QdrantClient + DEFAULT_DISTANCE = "Cosine" CONTENT_PAYLOAD_KEY = "data" @@ -56,9 +61,11 @@ class QdrantVectorStoreDriver(BaseVectorStoreDriver): collection_name: str = field(kw_only=True, metadata={"serializable": True}) vector_name: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": True}) content_payload_key: str = field(default=CONTENT_PAYLOAD_KEY, kw_only=True, metadata={"serializable": True}) + _client: QdrantClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) - def __attrs_post_init__(self) -> None: - self.client = import_optional_dependency("qdrant_client").QdrantClient( + @lazy_property() + def client(self) -> QdrantClient: + return import_optional_dependency("qdrant_client").QdrantClient( location=self.location, url=self.url, host=self.host, diff --git a/griptape/drivers/vector/redis_vector_store_driver.py b/griptape/drivers/vector/redis_vector_store_driver.py index 0abf2c9854..d220878f3f 100644 --- a/griptape/drivers/vector/redis_vector_store_driver.py +++ b/griptape/drivers/vector/redis_vector_store_driver.py @@ -4,10 +4,11 @@ from typing import TYPE_CHECKING, NoReturn, Optional import numpy as np -from attrs import Factory, define, field +from attrs import define, field from griptape.drivers import BaseVectorStoreDriver from griptape.utils import import_optional_dependency, str_to_hash +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from redis import Redis @@ -33,19 +34,17 @@ class RedisVectorStoreDriver(BaseVectorStoreDriver): db: int = field(kw_only=True, default=0, metadata={"serializable": True}) password: Optional[str] = field(default=None, kw_only=True, metadata={"serializable": False}) index: str = field(kw_only=True, metadata={"serializable": True}) - - client: Redis = field( - default=Factory( - lambda self: import_optional_dependency("redis").Redis( - host=self.host, - port=self.port, - db=self.db, - password=self.password, - decode_responses=False, - ), - takes_self=True, - ), - ) + _client: Redis = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> Redis: + return import_optional_dependency("redis").Redis( + host=self.host, + port=self.port, + db=self.db, + password=self.password, + decode_responses=False, + ) def upsert_vector( self, diff --git a/griptape/drivers/web_search/duck_duck_go_web_search_driver.py b/griptape/drivers/web_search/duck_duck_go_web_search_driver.py index b67e81f35c..96891c2d44 100644 --- a/griptape/drivers/web_search/duck_duck_go_web_search_driver.py +++ b/griptape/drivers/web_search/duck_duck_go_web_search_driver.py @@ -3,11 +3,12 @@ import json from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from griptape.artifacts import ListArtifact, TextArtifact from griptape.drivers import BaseWebSearchDriver from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from duckduckgo_search import DDGS @@ -15,7 +16,11 @@ @define class DuckDuckGoWebSearchDriver(BaseWebSearchDriver): - client: DDGS = field(default=Factory(lambda: import_optional_dependency("duckduckgo_search").DDGS()), kw_only=True) + _client: DDGS = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> DDGS: + return import_optional_dependency("duckduckgo_search").DDGS() def search(self, query: str, **kwargs) -> ListArtifact: try: diff --git a/griptape/schemas/base_schema.py b/griptape/schemas/base_schema.py index dde3ae49a8..4892cbf9bf 100644 --- a/griptape/schemas/base_schema.py +++ b/griptape/schemas/base_schema.py @@ -165,6 +165,13 @@ def _resolve_types(cls, attrs_cls: type) -> None: if is_dependency_installed("google.generativeai") else Any, "boto3": import_optional_dependency("boto3") if is_dependency_installed("boto3") else Any, + "Anthropic": import_optional_dependency("anthropic").Anthropic + if is_dependency_installed("anthropic") + else Any, + "BedrockClient": import_optional_dependency("mypy_boto3_bedrock").BedrockClient + if is_dependency_installed("mypy_boto3_bedrock") + else Any, + "voyageai": import_optional_dependency("voyageai") if is_dependency_installed("voyageai") else Any, }, ) diff --git a/griptape/tokenizers/google_tokenizer.py b/griptape/tokenizers/google_tokenizer.py index 87020bd967..144c09d754 100644 --- a/griptape/tokenizers/google_tokenizer.py +++ b/griptape/tokenizers/google_tokenizer.py @@ -2,10 +2,11 @@ from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from griptape.tokenizers import BaseTokenizer from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property if TYPE_CHECKING: from google.generativeai import GenerativeModel @@ -17,16 +18,14 @@ class GoogleTokenizer(BaseTokenizer): MODEL_PREFIXES_TO_MAX_OUTPUT_TOKENS = {"gemini": 2048} api_key: str = field(kw_only=True, metadata={"serializable": True}) - model_client: GenerativeModel = field( - default=Factory(lambda self: self._default_model_client(), takes_self=True), - kw_only=True, - ) + _client: GenerativeModel = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) - def count_tokens(self, text: str) -> int: - return self.model_client.count_tokens(text).total_tokens - - def _default_model_client(self) -> GenerativeModel: + @lazy_property() + def client(self) -> GenerativeModel: genai = import_optional_dependency("google.generativeai") genai.configure(api_key=self.api_key) return genai.GenerativeModel(self.model) + + def count_tokens(self, text: str) -> int: + return self.client.count_tokens(text).total_tokens diff --git a/griptape/tools/aws_iam/tool.py b/griptape/tools/aws_iam/tool.py index 8d22dd3c95..6c1bed054d 100644 --- a/griptape/tools/aws_iam/tool.py +++ b/griptape/tools/aws_iam/tool.py @@ -2,20 +2,24 @@ from typing import TYPE_CHECKING -from attrs import Factory, define, field +from attrs import define, field from schema import Literal, Schema from griptape.artifacts import ErrorArtifact, ListArtifact, TextArtifact from griptape.tools import BaseAwsTool -from griptape.utils.decorators import activity +from griptape.utils.decorators import activity, lazy_property if TYPE_CHECKING: - from mypy_boto3_iam import Client + from mypy_boto3_iam import IAMClient @define class AwsIamTool(BaseAwsTool): - iam_client: Client = field(default=Factory(lambda self: self.session.client("iam"), takes_self=True), kw_only=True) + _client: IAMClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> IAMClient: + return self.session.client("iam") @activity( config={ @@ -33,7 +37,7 @@ class AwsIamTool(BaseAwsTool): ) def get_user_policy(self, params: dict) -> TextArtifact | ErrorArtifact: try: - policy = self.iam_client.get_user_policy( + policy = self.client.get_user_policy( UserName=params["values"]["user_name"], PolicyName=params["values"]["policy_name"], ) @@ -44,7 +48,7 @@ def get_user_policy(self, params: dict) -> TextArtifact | ErrorArtifact: @activity(config={"description": "Can be used to list AWS MFA Devices"}) def list_mfa_devices(self, _: dict) -> ListArtifact | ErrorArtifact: try: - devices = self.iam_client.list_mfa_devices() + devices = self.client.list_mfa_devices() return ListArtifact([TextArtifact(str(d)) for d in devices["MFADevices"]]) except Exception as e: return ErrorArtifact(f"error listing mfa devices: {e}") @@ -59,10 +63,10 @@ def list_mfa_devices(self, _: dict) -> ListArtifact | ErrorArtifact: ) def list_user_policies(self, params: dict) -> ListArtifact | ErrorArtifact: try: - policies = self.iam_client.list_user_policies(UserName=params["values"]["user_name"]) + policies = self.client.list_user_policies(UserName=params["values"]["user_name"]) policy_names = policies["PolicyNames"] - attached_policies = self.iam_client.list_attached_user_policies(UserName=params["values"]["user_name"]) + attached_policies = self.client.list_attached_user_policies(UserName=params["values"]["user_name"]) attached_policy_names = [ p["PolicyName"] for p in attached_policies["AttachedPolicies"] if "PolicyName" in p ] @@ -74,7 +78,7 @@ def list_user_policies(self, params: dict) -> ListArtifact | ErrorArtifact: @activity(config={"description": "Can be used to list AWS IAM users."}) def list_users(self, _: dict) -> ListArtifact | ErrorArtifact: try: - users = self.iam_client.list_users() + users = self.client.list_users() return ListArtifact([TextArtifact(str(u)) for u in users["Users"]]) except Exception as e: return ErrorArtifact(f"error listing s3 users: {e}") diff --git a/griptape/tools/aws_s3/tool.py b/griptape/tools/aws_s3/tool.py index 24d091d711..b352da2d55 100644 --- a/griptape/tools/aws_s3/tool.py +++ b/griptape/tools/aws_s3/tool.py @@ -3,20 +3,24 @@ import io from typing import TYPE_CHECKING, Any -from attrs import Factory, define, field +from attrs import define, field from schema import Literal, Schema from griptape.artifacts import BlobArtifact, ErrorArtifact, InfoArtifact, ListArtifact, TextArtifact from griptape.tools import BaseAwsTool -from griptape.utils.decorators import activity +from griptape.utils.decorators import activity, lazy_property if TYPE_CHECKING: - from mypy_boto3_s3 import Client + from mypy_boto3_s3 import S3Client @define class AwsS3Tool(BaseAwsTool): - s3_client: Client = field(default=Factory(lambda self: self.session.client("s3"), takes_self=True), kw_only=True) + _client: S3Client = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> S3Client: + return self.session.client("s3") @activity( config={ @@ -33,7 +37,7 @@ class AwsS3Tool(BaseAwsTool): ) def get_bucket_acl(self, params: dict) -> TextArtifact | ErrorArtifact: try: - acl = self.s3_client.get_bucket_acl(Bucket=params["values"]["bucket_name"]) + acl = self.client.get_bucket_acl(Bucket=params["values"]["bucket_name"]) return TextArtifact(acl) except Exception as e: return ErrorArtifact(f"error getting bucket acl: {e}") @@ -48,7 +52,7 @@ def get_bucket_acl(self, params: dict) -> TextArtifact | ErrorArtifact: ) def get_bucket_policy(self, params: dict) -> TextArtifact | ErrorArtifact: try: - policy = self.s3_client.get_bucket_policy(Bucket=params["values"]["bucket_name"]) + policy = self.client.get_bucket_policy(Bucket=params["values"]["bucket_name"]) return TextArtifact(policy) except Exception as e: return ErrorArtifact(f"error getting bucket policy: {e}") @@ -66,7 +70,7 @@ def get_bucket_policy(self, params: dict) -> TextArtifact | ErrorArtifact: ) def get_object_acl(self, params: dict) -> TextArtifact | ErrorArtifact: try: - acl = self.s3_client.get_object_acl( + acl = self.client.get_object_acl( Bucket=params["values"]["bucket_name"], Key=params["values"]["object_key"], ) @@ -77,7 +81,7 @@ def get_object_acl(self, params: dict) -> TextArtifact | ErrorArtifact: @activity(config={"description": "Can be used to list all AWS S3 buckets."}) def list_s3_buckets(self, _: dict) -> ListArtifact | ErrorArtifact: try: - buckets = self.s3_client.list_buckets() + buckets = self.client.list_buckets() return ListArtifact([TextArtifact(str(b)) for b in buckets["Buckets"]]) except Exception as e: @@ -91,7 +95,7 @@ def list_s3_buckets(self, _: dict) -> ListArtifact | ErrorArtifact: ) def list_objects(self, params: dict) -> ListArtifact | ErrorArtifact: try: - objects = self.s3_client.list_objects_v2(Bucket=params["values"]["bucket_name"]) + objects = self.client.list_objects_v2(Bucket=params["values"]["bucket_name"]) if "Contents" not in objects: return ErrorArtifact("no objects found in the bucket") @@ -192,7 +196,7 @@ def download_objects(self, params: dict) -> ListArtifact | ErrorArtifact: artifacts = [] for object_info in objects: try: - obj = self.s3_client.get_object(Bucket=object_info["bucket_name"], Key=object_info["object_key"]) + obj = self.client.get_object(Bucket=object_info["bucket_name"], Key=object_info["object_key"]) content = obj["Body"].read() artifacts.append(BlobArtifact(content, name=object_info["object_key"])) @@ -203,9 +207,9 @@ def download_objects(self, params: dict) -> ListArtifact | ErrorArtifact: return ListArtifact(artifacts) def _upload_object(self, bucket_name: str, object_name: str, value: Any) -> None: - self.s3_client.create_bucket(Bucket=bucket_name) + self.client.create_bucket(Bucket=bucket_name) - self.s3_client.upload_fileobj( + self.client.upload_fileobj( Fileobj=io.BytesIO(value.encode() if isinstance(value, str) else value), Bucket=bucket_name, Key=object_name, diff --git a/poetry.lock b/poetry.lock index 68d13fd05f..d04582db9e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -380,10 +380,14 @@ files = [ [package.dependencies] botocore-stubs = "*" mypy-boto3-bedrock = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"bedrock\""} +mypy-boto3-dynamodb = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"dynamodb\""} mypy-boto3-iam = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"iam\""} +mypy-boto3-iot-data = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"iot-data\""} mypy-boto3-opensearch = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"opensearch\""} +mypy-boto3-redshift-data = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"redshift-data\""} mypy-boto3-s3 = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"s3\""} mypy-boto3-sagemaker = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"sagemaker\""} +mypy-boto3-sqs = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"sqs\""} types-s3transfer = "*" typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} @@ -3387,6 +3391,20 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} +[[package]] +name = "mypy-boto3-dynamodb" +version = "1.35.24" +description = "Type annotations for boto3.DynamoDB 1.35.24 service generated with mypy-boto3-builder 8.1.1" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_boto3_dynamodb-1.35.24-py3-none-any.whl", hash = "sha256:022859543c5314f14fb03ef4e445e34b97b9bc0cecb003c14c10943a2eaa3ff7"}, + {file = "mypy_boto3_dynamodb-1.35.24.tar.gz", hash = "sha256:55bf897a1d0e354579edb05001f4bc4f472b9452badd9db24876c31bdf3f72a1"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + [[package]] name = "mypy-boto3-iam" version = "1.35.0" @@ -3401,6 +3419,20 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} +[[package]] +name = "mypy-boto3-iot-data" +version = "1.35.0" +description = "Type annotations for boto3.IoTDataPlane 1.35.0 service generated with mypy-boto3-builder 7.26.0" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_boto3_iot_data-1.35.0-py3-none-any.whl", hash = "sha256:1f442679a71f22a82b0436ee4f71c06104a9ed722aa71c6800fd93bd345cfc03"}, + {file = "mypy_boto3_iot_data-1.35.0.tar.gz", hash = "sha256:e83cbbd948bc388ed139d2820442af1d319ca37dce708df44295c4acfcfb30f8"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + [[package]] name = "mypy-boto3-opensearch" version = "1.35.0" @@ -3415,6 +3447,20 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} +[[package]] +name = "mypy-boto3-redshift-data" +version = "1.35.10" +description = "Type annotations for boto3.RedshiftDataAPIService 1.35.10 service generated with mypy-boto3-builder 7.26.1" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_boto3_redshift_data-1.35.10-py3-none-any.whl", hash = "sha256:1d37d8453c4f3e6b688703a91316729ee2dcaec101326c4f58658d8526d5fc09"}, + {file = "mypy_boto3_redshift_data-1.35.10.tar.gz", hash = "sha256:2cfe518ef3027c2b050facffd2621924458ddf2fb3df9699cdba33e8a6859594"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + [[package]] name = "mypy-boto3-s3" version = "1.35.2" @@ -3443,6 +3489,20 @@ files = [ [package.dependencies] typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} +[[package]] +name = "mypy-boto3-sqs" +version = "1.35.0" +description = "Type annotations for boto3.SQS 1.35.0 service generated with mypy-boto3-builder 7.26.0" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_boto3_sqs-1.35.0-py3-none-any.whl", hash = "sha256:9fd6e622ed231c06f7542ba6f8f0eea92046cace24defa95d0d0ce04e7caee0c"}, + {file = "mypy_boto3_sqs-1.35.0.tar.gz", hash = "sha256:61752f1c2bf2efa3815f64d43c25b4a39dbdbd9e472ae48aa18d7c6d2a7a6eb8"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + [[package]] name = "ndg-httpsclient" version = "0.5.1" @@ -6391,6 +6451,11 @@ files = [ {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, + {file = "triton-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b052da883351fdf6be3d93cedae6db3b8e3988d3b09ed221bccecfa9612230"}, + {file = "triton-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd34f19a8582af96e6291d4afce25dac08cb2a5d218c599163761e8e0827208e"}, + {file = "triton-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d5e10de8c011adeb7c878c6ce0dd6073b14367749e34467f1cff2bde1b78253"}, + {file = "triton-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8903767951bf86ec960b4fe4e21bc970055afc65e9d57e916d79ae3c93665e3"}, + {file = "triton-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41004fb1ae9a53fcb3e970745feb87f0e3c94c6ce1ba86e95fa3b8537894bef7"}, ] [package.dependencies] @@ -7024,4 +7089,4 @@ loaders-sql = ["sqlalchemy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "bb4af9c531d0029cb1baeca3a2e94566aaf6d7cb701a6dc07f5e9983bffd1285" +content-hash = "96cb1c9cb807d112d5b6fdae19b99fad98de4f82ab73ae8b24d313dd5d7ff773" diff --git a/pyproject.toml b/pyproject.toml index 591ebc3cde..d5086386e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -228,7 +228,7 @@ optional = true ruff = "^0.6.0" pyright = "^1.1.376" pre-commit = "^3.7.1" -boto3-stubs = {extras = ["bedrock", "iam", "opensearch", "s3", "sagemaker"], version = "^1.34.105"} +boto3-stubs = {extras = ["bedrock", "iam", "opensearch", "s3", "sagemaker", "sqs", "iot-data", "dynamodb", "redshift-data"], version = "^1.34.105"} typos = "^1.22.9" diff --git a/tests/unit/drivers/event_listener/test_pusher_event_listener_driver.py b/tests/unit/drivers/event_listener/test_pusher_event_listener_driver.py index 50856c0da1..4168f762d6 100644 --- a/tests/unit/drivers/event_listener/test_pusher_event_listener_driver.py +++ b/tests/unit/drivers/event_listener/test_pusher_event_listener_driver.py @@ -9,11 +9,11 @@ class TestPusherEventListenerDriver: @pytest.fixture(autouse=True) def mock_post(self, mocker): - mock_pusher_client = mocker.patch("pusher.Pusher") - mock_pusher_client.return_value.trigger.return_value = Mock() - mock_pusher_client.return_value.trigger_batch.return_value = Mock() + mock_client = mocker.patch("pusher.Pusher") + mock_client.return_value.trigger.return_value = Mock() + mock_client.return_value.trigger_batch.return_value = Mock() - return mock_pusher_client + return mock_client @pytest.fixture() def driver(self): @@ -33,12 +33,12 @@ def test_try_publish_event_payload(self, driver): data = MockEvent().to_dict() driver.try_publish_event_payload(data) - driver.pusher_client.trigger.assert_called_with(channels="test-channel", event_name="test-event", data=data) + driver.client.trigger.assert_called_with(channels="test-channel", event_name="test-event", data=data) def test_try_publish_event_payload_batch(self, driver): data = [MockEvent().to_dict() for _ in range(3)] driver.try_publish_event_payload_batch(data) - driver.pusher_client.trigger_batch.assert_called_with( + driver.client.trigger_batch.assert_called_with( [{"channel": "test-channel", "name": "test-event", "data": data[i]} for i in range(3)] ) diff --git a/tests/unit/drivers/image_generation/test_amazon_bedrock_stable_diffusion_image_generation_driver.py b/tests/unit/drivers/image_generation/test_amazon_bedrock_stable_diffusion_image_generation_driver.py index 05e669b661..dae6f695b8 100644 --- a/tests/unit/drivers/image_generation/test_amazon_bedrock_stable_diffusion_image_generation_driver.py +++ b/tests/unit/drivers/image_generation/test_amazon_bedrock_stable_diffusion_image_generation_driver.py @@ -8,13 +8,13 @@ class TestAmazonBedrockImageGenerationDriver: @pytest.fixture() - def bedrock_client(self): + def client(self): return Mock() @pytest.fixture() - def session(self, bedrock_client): + def session(self, client): session = Mock() - session.client.return_value = bedrock_client + session.client.return_value = client return session @@ -40,7 +40,7 @@ def test_init_requires_image_generation_model_driver(self, session): AmazonBedrockImageGenerationDriver(session=session, model="stability.stable-diffusion-xl-v1") # pyright: ignore[reportCallIssue] def test_try_text_to_image(self, driver): - driver.bedrock_client.invoke_model.return_value = { + driver.client.invoke_model.return_value = { "body": io.BytesIO( b"""{ "artifacts": [ diff --git a/tests/unit/drivers/image_query/test_amazon_bedrock_image_query_driver.py b/tests/unit/drivers/image_query/test_amazon_bedrock_image_query_driver.py index 9493ab23de..66b23d0c38 100644 --- a/tests/unit/drivers/image_query/test_amazon_bedrock_image_query_driver.py +++ b/tests/unit/drivers/image_query/test_amazon_bedrock_image_query_driver.py @@ -9,13 +9,13 @@ class TestAmazonBedrockImageQueryDriver: @pytest.fixture() - def bedrock_client(self, mocker): + def client(self, mocker): return Mock() @pytest.fixture() - def session(self, bedrock_client): + def session(self, client): session = Mock() - session.client.return_value = bedrock_client + session.client.return_value = client return session @@ -35,7 +35,7 @@ def test_init(self, image_query_driver): assert image_query_driver def test_try_query(self, image_query_driver): - image_query_driver.bedrock_client.invoke_model.return_value = {"body": io.BytesIO(b"""{"content": []}""")} + image_query_driver.client.invoke_model.return_value = {"body": io.BytesIO(b"""{"content": []}""")} text_artifact = image_query_driver.try_query( "Prompt String", [ImageArtifact(value=b"test-data", width=100, height=100, format="png")] @@ -44,7 +44,7 @@ def test_try_query(self, image_query_driver): assert text_artifact.value == "content" def test_try_query_no_body(self, image_query_driver): - image_query_driver.bedrock_client.invoke_model.return_value = {"body": io.BytesIO(b"")} + image_query_driver.client.invoke_model.return_value = {"body": io.BytesIO(b"")} with pytest.raises(ValueError): image_query_driver.try_query( diff --git a/tests/unit/drivers/vector/test_marqo_vector_store_driver.py b/tests/unit/drivers/vector/test_marqo_vector_store_driver.py index 254a2b3a16..2d824e1c29 100644 --- a/tests/unit/drivers/vector/test_marqo_vector_store_driver.py +++ b/tests/unit/drivers/vector/test_marqo_vector_store_driver.py @@ -86,7 +86,7 @@ def driver(self, mock_marqo): api_key="foobar", url="http://localhost:8000", index="test", - mq=mock_marqo, + client=mock_marqo, embedding_driver=MockEmbeddingDriver(), ) diff --git a/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py b/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py index 0726a0c7ea..a963fb370e 100644 --- a/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py +++ b/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py @@ -7,7 +7,7 @@ class TestPineconeVectorStorageDriver: @pytest.fixture(autouse=True) - def _mock_pinecone(self, mocker): + def mock_index(self, mocker): # Create a fake response fake_query_response = { "matches": [{"id": "foo", "values": [0, 1, 0], "score": 42, "metadata": {"foo": "bar"}}], @@ -15,14 +15,21 @@ def _mock_pinecone(self, mocker): } mock_client = mocker.patch("pinecone.Pinecone") - mock_client().Index().upsert.return_value = None - mock_client().Index().query.return_value = fake_query_response - mock_client().create_index.return_value = None + mock_index = mock_client().Index() + mock_index.upsert.return_value = None + mock_index.query.return_value = fake_query_response + mock_index.create_index.return_value = None + + return mock_index @pytest.fixture() - def driver(self): + def driver(self, mock_index): return PineconeVectorStoreDriver( - api_key="foobar", index_name="test", environment="test", embedding_driver=MockEmbeddingDriver() + api_key="foobar", + index_name="test", + environment="test", + embedding_driver=MockEmbeddingDriver(), + index=mock_index, ) def test_upsert_text_artifact(self, driver): diff --git a/tests/unit/drivers/vector/test_qdrant_vector_store_driver.py b/tests/unit/drivers/vector/test_qdrant_vector_store_driver.py index ffb3599533..3c14f23962 100644 --- a/tests/unit/drivers/vector/test_qdrant_vector_store_driver.py +++ b/tests/unit/drivers/vector/test_qdrant_vector_store_driver.py @@ -37,30 +37,6 @@ def driver(self, embedding_driver, mocker): embedding_driver=embedding_driver, ) - def test_attrs_post_init(self, driver): - with patch("griptape.drivers.vector.qdrant_vector_store_driver.import_optional_dependency") as mock_import: - mock_qdrant_client = MagicMock() - mock_import.return_value.QdrantClient.return_value = mock_qdrant_client - - driver.__attrs_post_init__() - - mock_import.assert_called_once_with("qdrant_client") - mock_import.return_value.QdrantClient.assert_called_once_with( - location=driver.location, - url=driver.url, - host=driver.host, - path=driver.path, - port=driver.port, - prefer_grpc=driver.prefer_grpc, - grpc_port=driver.grpc_port, - api_key=driver.api_key, - https=driver.https, - prefix=driver.prefix, - force_disable_check_same_thread=driver.force_disable_check_same_thread, - timeout=driver.timeout, - ) - assert driver.client == mock_qdrant_client - def test_delete_vector(self, driver): vector_id = "test_vector_id" From bea6263b045bfeaab4ad3adf08055a356e20b394 Mon Sep 17 00:00:00 2001 From: Matt Vallillo Date: Mon, 23 Sep 2024 18:46:07 -0400 Subject: [PATCH 5/8] Fix Pinecone Index (#1200) --- .../drivers/vector/pinecone_vector_store_driver.py | 2 +- .../vector/test_pinecone_vector_storage_driver.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/griptape/drivers/vector/pinecone_vector_store_driver.py b/griptape/drivers/vector/pinecone_vector_store_driver.py index 500b090f58..81e593e729 100644 --- a/griptape/drivers/vector/pinecone_vector_store_driver.py +++ b/griptape/drivers/vector/pinecone_vector_store_driver.py @@ -31,7 +31,7 @@ def client(self) -> pinecone.Pinecone: @lazy_property() def index(self) -> pinecone.Index: - return self.client.get_index(self.index_name) + return self.client.Index(self.index_name) def upsert_vector( self, diff --git a/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py b/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py index a963fb370e..8be38c51e8 100644 --- a/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py +++ b/tests/unit/drivers/vector/test_pinecone_vector_storage_driver.py @@ -7,7 +7,7 @@ class TestPineconeVectorStorageDriver: @pytest.fixture(autouse=True) - def mock_index(self, mocker): + def mock_client(self, mocker): # Create a fake response fake_query_response = { "matches": [{"id": "foo", "values": [0, 1, 0], "score": 42, "metadata": {"foo": "bar"}}], @@ -20,16 +20,19 @@ def mock_index(self, mocker): mock_index.query.return_value = fake_query_response mock_index.create_index.return_value = None - return mock_index + # Return the mock index when the Pinecone client is called + mock_client.Index.return_value = mock_index + + return mock_client @pytest.fixture() - def driver(self, mock_index): + def driver(self, mock_client): return PineconeVectorStoreDriver( api_key="foobar", index_name="test", environment="test", embedding_driver=MockEmbeddingDriver(), - index=mock_index, + client=mock_client, ) def test_upsert_text_artifact(self, driver): From a3cdbf975de88e44c41e8403eed56f75d5a84c07 Mon Sep 17 00:00:00 2001 From: William Price <82848178+william-price01@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:40:56 -0700 Subject: [PATCH 6/8] Feature/Tavily Web Search Driver (#1179) --- CHANGELOG.md | 1 + .../drivers/src/web_search_drivers_4.py | 7 ++ .../drivers/src/web_search_drivers_5.py | 9 +++ .../drivers/web-search-drivers.md | 60 +++++++++++++--- griptape/drivers/__init__.py | 2 + .../web_search/base_web_search_driver.py | 2 - .../duck_duck_go_web_search_driver.py | 2 + .../web_search/google_web_search_driver.py | 2 + .../web_search/tavily_web_search_driver.py | 29 ++++++++ poetry.lock | 39 +++++----- pyproject.toml | 3 + .../test_tavily_web_search_driver.py | 72 +++++++++++++++++++ 12 files changed, 198 insertions(+), 30 deletions(-) create mode 100644 docs/griptape-framework/drivers/src/web_search_drivers_4.py create mode 100644 docs/griptape-framework/drivers/src/web_search_drivers_5.py create mode 100644 griptape/drivers/web_search/tavily_web_search_driver.py create mode 100644 tests/unit/drivers/web_search/test_tavily_web_search_driver.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 289ec72d86..4f470f02e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Added - Parameter `pipeline_task` on `HuggingFacePipelinePromptDriver` for creating different types of `Pipeline`s. +- `TavilyWebSearchDriver` to integrate Tavily's web search capabilities. ### Changed - **BREAKING**: Renamed parameters on several classes to `client`: diff --git a/docs/griptape-framework/drivers/src/web_search_drivers_4.py b/docs/griptape-framework/drivers/src/web_search_drivers_4.py new file mode 100644 index 0000000000..1119f8bed2 --- /dev/null +++ b/docs/griptape-framework/drivers/src/web_search_drivers_4.py @@ -0,0 +1,7 @@ +import os + +from griptape.drivers import TavilyWebSearchDriver + +driver = TavilyWebSearchDriver(api_key=os.environ["TAVILY_API_KEY"]) + +driver.search("griptape ai") diff --git a/docs/griptape-framework/drivers/src/web_search_drivers_5.py b/docs/griptape-framework/drivers/src/web_search_drivers_5.py new file mode 100644 index 0000000000..fd880736bc --- /dev/null +++ b/docs/griptape-framework/drivers/src/web_search_drivers_5.py @@ -0,0 +1,9 @@ +from griptape.drivers import DuckDuckGoWebSearchDriver +from griptape.structures import Agent +from griptape.tools import PromptSummaryTool, WebSearchTool + +agent = Agent( + tools=[WebSearchTool(web_search_driver=DuckDuckGoWebSearchDriver()), PromptSummaryTool(off_prompt=False)], +) + +agent.run("Give me some websites with information about AI frameworks.") diff --git a/docs/griptape-framework/drivers/web-search-drivers.md b/docs/griptape-framework/drivers/web-search-drivers.md index b2400fe28f..ca65bfd8e4 100644 --- a/docs/griptape-framework/drivers/web-search-drivers.md +++ b/docs/griptape-framework/drivers/web-search-drivers.md @@ -1,6 +1,6 @@ --- search: - boost: 2 + boost: 2 --- ## Overview @@ -9,7 +9,47 @@ Web Search Drivers can be used to search for links from a search query. They are * `search()` searches the web and returns a [ListArtifact](../../reference/griptape/artifacts/list_artifact.md) that contains JSON-serializable [TextArtifact](../../reference/griptape/artifacts/text_artifact.md)s with the search results. -## Vector Store Drivers +You can use Web Search Drivers with [Structures](../structures/agents.md): + +```python +--8<-- "docs/griptape-framework/drivers/src/web_search_drivers_5.py" +``` +``` +ToolkitTask 45a53f1024494baab41a1f10a67017b1 + Output: Here are some websites with information about AI + frameworks: + + 1. [The Top 16 AI Frameworks and Libraries: A Beginner's Guide - + DataCamp](https://www.datacamp.com/blog/top-ai-frameworks-and-lib + raries) + 2. [AI Frameworks: Top Types To Adopt in 2024 - + Splunk](https://www.splunk.com/en_us/blog/learn/ai-frameworks.htm + l) + 3. [Top AI Frameworks in 2024: A Review - + BairesDev](https://www.bairesdev.com/blog/ai-frameworks/) + 4. [The Top 16 AI Frameworks and Libraries - AI + Slackers](https://aislackers.com/the-top-16-ai-frameworks-and-lib + raries/) + 5. [Top AI Frameworks in 2024: Artificial Intelligence Frameworks + Comparison - Clockwise + Software](https://clockwise.software/blog/artificial-intelligence + -framework/) +``` +Or use them independently: + +```python +--8<-- "docs/griptape-framework/drivers/src/web_search_drivers_3.py" +``` +``` +{"title": "The Top 16 AI Frameworks and Libraries: A Beginner's Guide", "url": "https://www.datacamp.com/blog/top-ai-frameworks-and-libraries", "description": "PyTorch. Torch is an open-source machine learning library known for its dynamic computational graph and is favored by researchers. The framework is excellent for prototyping and experimentation. Moreover, it's empowered by growing community support, with tools like PyTorch being built on the library."} + +{"title": "Top 11 AI Frameworks and Tools in 2024 | Fively | 5ly.co", "url": "https://5ly.co/blog/best-ai-frameworks/", "description": "Discover the top 11 modern artificial intelligence tools and frameworks to build robust architectures for your AI-powered apps. ... - Some advanced use cases may need further fine-tuning. Caffe 2. Now we move on to deep learning tools and frameworks. The first one is Caffe 2: an open-source deep learning framework with modularity and speed in ..."} + +{"title": "The Top 16 AI Frameworks and Libraries | AI Slackers", "url": "https://aislackers.com/the-top-16-ai-frameworks-and-libraries/", "description": "Experiment with different frameworks to find the one that aligns with your needs and goals as a data practitioner. Embrace the world of AI frameworks, and embark on a journey of building smarter software with confidence. Discover the top AI frameworks and libraries like PyTorch, Scikit-Learn, TensorFlow, Keras, LangChain, and more."} +``` + + +## Web Search Drivers ### Google @@ -21,12 +61,6 @@ Example using `GoogleWebSearchDriver` directly: --8<-- "docs/griptape-framework/drivers/src/web_search_drivers_1.py" ``` -Example of using `GoogleWebSearchDriver` with an agent: - -```python ---8<-- "docs/griptape-framework/drivers/src/web_search_drivers_2.py" -``` - ### DuckDuckGo !!! info @@ -39,3 +73,13 @@ Example of using `DuckDuckGoWebSearchDriver` directly: ```python --8<-- "docs/griptape-framework/drivers/src/web_search_drivers_3.py" ``` + +### Tavily +!!! info + This driver requires the `drivers-web-search-tavily` [extra](../index.md#extras), and a Tavily [api key](https://app.tavily.com). + +Example of using `TavilyWebSearchDriver` directly: + +```python +--8<-- "docs/griptape-framework/drivers/src/web_search_drivers_4.py" +``` \ No newline at end of file diff --git a/griptape/drivers/__init__.py b/griptape/drivers/__init__.py index 7d2de3552e..8eb03a622b 100644 --- a/griptape/drivers/__init__.py +++ b/griptape/drivers/__init__.py @@ -99,6 +99,7 @@ from .web_search.base_web_search_driver import BaseWebSearchDriver from .web_search.google_web_search_driver import GoogleWebSearchDriver from .web_search.duck_duck_go_web_search_driver import DuckDuckGoWebSearchDriver +from .web_search.tavily_web_search_driver import TavilyWebSearchDriver from .event_listener.base_event_listener_driver import BaseEventListenerDriver from .event_listener.amazon_sqs_event_listener_driver import AmazonSqsEventListenerDriver @@ -213,6 +214,7 @@ "BaseWebSearchDriver", "GoogleWebSearchDriver", "DuckDuckGoWebSearchDriver", + "TavilyWebSearchDriver", "BaseEventListenerDriver", "AmazonSqsEventListenerDriver", "WebhookEventListenerDriver", diff --git a/griptape/drivers/web_search/base_web_search_driver.py b/griptape/drivers/web_search/base_web_search_driver.py index b561085ef0..bb88735c52 100644 --- a/griptape/drivers/web_search/base_web_search_driver.py +++ b/griptape/drivers/web_search/base_web_search_driver.py @@ -8,8 +8,6 @@ @define class BaseWebSearchDriver(ABC): results_count: int = field(default=5, kw_only=True) - language: str = field(default="en", kw_only=True) - country: str = field(default="us", kw_only=True) @abstractmethod def search(self, query: str, **kwargs) -> ListArtifact: ... diff --git a/griptape/drivers/web_search/duck_duck_go_web_search_driver.py b/griptape/drivers/web_search/duck_duck_go_web_search_driver.py index 96891c2d44..113ca5a8aa 100644 --- a/griptape/drivers/web_search/duck_duck_go_web_search_driver.py +++ b/griptape/drivers/web_search/duck_duck_go_web_search_driver.py @@ -16,6 +16,8 @@ @define class DuckDuckGoWebSearchDriver(BaseWebSearchDriver): + language: str = field(default="en", kw_only=True) + country: str = field(default="us", kw_only=True) _client: DDGS = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) @lazy_property() diff --git a/griptape/drivers/web_search/google_web_search_driver.py b/griptape/drivers/web_search/google_web_search_driver.py index 012c52307a..e16e87f333 100644 --- a/griptape/drivers/web_search/google_web_search_driver.py +++ b/griptape/drivers/web_search/google_web_search_driver.py @@ -13,6 +13,8 @@ class GoogleWebSearchDriver(BaseWebSearchDriver): api_key: str = field(kw_only=True) search_id: str = field(kw_only=True) + language: str = field(default="en", kw_only=True) + country: str = field(default="us", kw_only=True) def search(self, query: str, **kwargs) -> ListArtifact: return ListArtifact([TextArtifact(json.dumps(result)) for result in self._search_google(query, **kwargs)]) diff --git a/griptape/drivers/web_search/tavily_web_search_driver.py b/griptape/drivers/web_search/tavily_web_search_driver.py new file mode 100644 index 0000000000..d3ecb0b4c3 --- /dev/null +++ b/griptape/drivers/web_search/tavily_web_search_driver.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from attrs import define, field + +from griptape.artifacts import JsonArtifact, ListArtifact +from griptape.drivers import BaseWebSearchDriver +from griptape.utils import import_optional_dependency +from griptape.utils.decorators import lazy_property + +if TYPE_CHECKING: + from tavily import TavilyClient + + +@define +class TavilyWebSearchDriver(BaseWebSearchDriver): + api_key: str = field(kw_only=True) + params: dict[str, Any] = field(factory=dict, kw_only=True, metadata={"serializable": True}) + _client: TavilyClient = field(default=None, kw_only=True, alias="client", metadata={"serializable": False}) + + @lazy_property() + def client(self) -> TavilyClient: + return import_optional_dependency("tavily").TavilyClient(self.api_key) + + def search(self, query: str, **kwargs) -> ListArtifact: + response = self.client.search(query, max_results=self.results_count, **self.params, **kwargs) + results = response.get("results", []) + return ListArtifact([(JsonArtifact(result)) for result in results]) diff --git a/poetry.lock b/poetry.lock index d04582db9e..7ca603031e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -5938,52 +5938,39 @@ python-versions = ">=3.7" files = [ {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b"}, {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea"}, {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9"}, {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff"}, {file = "SQLAlchemy-2.0.35-cp310-cp310-win32.whl", hash = "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b"}, {file = "SQLAlchemy-2.0.35-cp310-cp310-win_amd64.whl", hash = "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-win32.whl", hash = "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e"}, {file = "SQLAlchemy-2.0.35-cp311-cp311-win_amd64.whl", hash = "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-win32.whl", hash = "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf"}, {file = "SQLAlchemy-2.0.35-cp312-cp312-win_amd64.whl", hash = "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc"}, {file = "SQLAlchemy-2.0.35-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1"}, {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3"}, {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f"}, {file = "SQLAlchemy-2.0.35-cp37-cp37m-win32.whl", hash = "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87"}, {file = "SQLAlchemy-2.0.35-cp37-cp37m-win_amd64.whl", hash = "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-win32.whl", hash = "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0"}, {file = "SQLAlchemy-2.0.35-cp38-cp38-win_amd64.whl", hash = "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-win32.whl", hash = "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3"}, {file = "SQLAlchemy-2.0.35-cp39-cp39-win_amd64.whl", hash = "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f"}, - {file = "SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1"}, {file = "sqlalchemy-2.0.35.tar.gz", hash = "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f"}, ] @@ -6043,6 +6030,22 @@ mpmath = ">=1.1.0,<1.4" [package.extras] dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] +[[package]] +name = "tavily-python" +version = "0.5.0" +description = "Python wrapper for the Tavily API" +optional = true +python-versions = ">=3.6" +files = [ + {file = "tavily_python-0.5.0-py3-none-any.whl", hash = "sha256:e874f6a04a56cdda80a505fe0b4f5d61d25372bd52a83e6773926fb297dcaa29"}, + {file = "tavily_python-0.5.0.tar.gz", hash = "sha256:2c60b88203b630e1b37fc711913a1090ced6719b3f21089f25ec06e9e1602822"}, +] + +[package.dependencies] +httpx = "*" +requests = "*" +tiktoken = ">=0.5.1" + [[package]] name = "tenacity" version = "8.5.0" @@ -6451,11 +6454,6 @@ files = [ {file = "triton-3.0.0-1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e509deb77f1c067d8640725ef00c5cbfcb2052a1a3cb6a6d343841f92624eb"}, {file = "triton-3.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bcbf3b1c48af6a28011a5c40a5b3b9b5330530c3827716b5fbf6d7adcc1e53e9"}, {file = "triton-3.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6e5727202f7078c56f91ff13ad0c1abab14a0e7f2c87e91b12b6f64f3e8ae609"}, - {file = "triton-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39b052da883351fdf6be3d93cedae6db3b8e3988d3b09ed221bccecfa9612230"}, - {file = "triton-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd34f19a8582af96e6291d4afce25dac08cb2a5d218c599163761e8e0827208e"}, - {file = "triton-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d5e10de8c011adeb7c878c6ce0dd6073b14367749e34467f1cff2bde1b78253"}, - {file = "triton-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8903767951bf86ec960b4fe4e21bc970055afc65e9d57e916d79ae3c93665e3"}, - {file = "triton-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41004fb1ae9a53fcb3e970745feb87f0e3c94c6ce1ba86e95fa3b8537894bef7"}, ] [package.dependencies] @@ -7037,7 +7035,7 @@ doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linke test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] -all = ["accelerate", "anthropic", "astrapy", "beautifulsoup4", "boto3", "cohere", "diffusers", "duckduckgo-search", "elevenlabs", "filetype", "google-generativeai", "mail-parser", "markdownify", "marqo", "ollama", "opensearch-py", "opentelemetry-api", "opentelemetry-exporter-otlp-proto-http", "opentelemetry-instrumentation", "opentelemetry-instrumentation-threading", "opentelemetry-sdk", "pandas", "pgvector", "pillow", "pinecone-client", "playwright", "psycopg2-binary", "pusher", "pymongo", "pypdf", "qdrant-client", "redis", "sentencepiece", "snowflake-sqlalchemy", "sqlalchemy", "torch", "trafilatura", "transformers", "voyageai"] +all = ["accelerate", "anthropic", "astrapy", "beautifulsoup4", "boto3", "cohere", "diffusers", "duckduckgo-search", "elevenlabs", "filetype", "google-generativeai", "mail-parser", "markdownify", "marqo", "ollama", "opensearch-py", "opentelemetry-api", "opentelemetry-exporter-otlp-proto-http", "opentelemetry-instrumentation", "opentelemetry-instrumentation-threading", "opentelemetry-sdk", "pandas", "pgvector", "pillow", "pinecone-client", "playwright", "psycopg2-binary", "pusher", "pymongo", "pypdf", "qdrant-client", "redis", "sentencepiece", "snowflake-sqlalchemy", "sqlalchemy", "tavily-python", "torch", "trafilatura", "transformers", "voyageai"] drivers-embedding-amazon-bedrock = ["boto3"] drivers-embedding-amazon-sagemaker = ["boto3"] drivers-embedding-cohere = ["cohere"] @@ -7079,6 +7077,7 @@ drivers-vector-redis = ["redis"] drivers-web-scraper-markdownify = ["beautifulsoup4", "markdownify", "playwright"] drivers-web-scraper-trafilatura = ["trafilatura"] drivers-web-search-duckduckgo = ["duckduckgo-search"] +drivers-web-search-tavily = ["tavily-python"] loaders-audio = ["filetype"] loaders-dataframe = ["pandas"] loaders-email = ["mail-parser"] @@ -7089,4 +7088,4 @@ loaders-sql = ["sqlalchemy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "96cb1c9cb807d112d5b6fdae19b99fad98de4f82ab73ae8b24d313dd5d7ff773" +content-hash = "310d1144f8393faf5b82f05e89270e930f8e25eb9d2036d5e1ca11a9b60cdc67" diff --git a/pyproject.toml b/pyproject.toml index d5086386e2..23471b71c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,7 @@ diffusers = {version = ">=0.29.1,<0.31.0", optional = true} accelerate = {version = ">=0.32.1,<0.35.0", optional = true} sentencepiece = {version = "^0.2.0", optional = true} torch = {version = "^2.3.1", optional = true} +tavily-python = {version = "^0.5.0", optional = true} # loaders pandas = {version = "^1.3", optional = true} @@ -111,6 +112,7 @@ drivers-web-scraper-trafilatura = ["trafilatura"] drivers-web-scraper-markdownify = ["playwright", "beautifulsoup4", "markdownify"] drivers-web-search-duckduckgo = ["duckduckgo-search"] +drivers-web-search-tavily = ["tavily-python"] drivers-event-listener-amazon-sqs = ["boto3"] drivers-event-listener-amazon-iot = ["boto3"] @@ -186,6 +188,7 @@ all = [ "pusher", "ollama", "duckduckgo-search", + "tavily-python", "opentelemetry-sdk", "opentelemetry-api", "opentelemetry-instrumentation", diff --git a/tests/unit/drivers/web_search/test_tavily_web_search_driver.py b/tests/unit/drivers/web_search/test_tavily_web_search_driver.py new file mode 100644 index 0000000000..eed66e5202 --- /dev/null +++ b/tests/unit/drivers/web_search/test_tavily_web_search_driver.py @@ -0,0 +1,72 @@ +import pytest + +from griptape.artifacts import ListArtifact +from griptape.drivers import TavilyWebSearchDriver + + +class TestTavilyWebSearchDriver: + @pytest.fixture() + def mock_tavily_client(self, mocker): + return mocker.patch("tavily.TavilyClient") + + @pytest.fixture() + def driver(self, mock_tavily_client): + mock_response = { + "results": [ + {"title": "foo", "url": "bar", "content": "baz"}, + {"title": "foo2", "url": "bar2", "content": "baz2"}, + ] + } + mock_tavily_client.return_value.search.return_value = mock_response + return TavilyWebSearchDriver(api_key="test") + + def test_search_returns_results(self, driver, mock_tavily_client): + results = driver.search("test") + assert isinstance(results, ListArtifact) + output = [result.value for result in results] + assert len(output) == 2 + assert output[0]["title"] == "foo" + assert output[0]["url"] == "bar" + assert output[0]["content"] == "baz" + mock_tavily_client.return_value.search.assert_called_once_with("test", max_results=5) + + def test_search_raises_error(self, mock_tavily_client): + mock_tavily_client.return_value.search.side_effect = Exception("test_error") + driver = TavilyWebSearchDriver(api_key="test") + with pytest.raises(Exception, match="test_error"): + driver.search("test") + + def test_search_with_params(self, mock_tavily_client): + mock_response = { + "results": [ + {"title": "custom", "url": "custom_url", "content": "custom_content"}, + ] + } + mock_tavily_client.return_value.search.return_value = mock_response + + driver = TavilyWebSearchDriver(api_key="test", params={"custom_param": "value"}) + results = driver.search("test", additional_param="extra") + + assert isinstance(results, ListArtifact) + output = results[0].value + assert output["title"] == "custom" + assert output["url"] == "custom_url" + assert output["content"] == "custom_content" + + mock_tavily_client.return_value.search.assert_called_once_with( + "test", max_results=5, custom_param="value", additional_param="extra" + ) + + def test_custom_results_count(self, mock_tavily_client): + mock_response = { + "results": [{"title": f"title_{i}", "url": f"url_{i}", "content": f"content_{i}"} for i in range(5)] + } + mock_tavily_client.return_value.search.return_value = mock_response + + driver = TavilyWebSearchDriver(api_key="test", results_count=5) + results = driver.search("test") + + assert isinstance(results, ListArtifact) + assert len(results) == 5 + + mock_tavily_client.return_value.search.assert_called_once_with("test", max_results=5) From 2d04000de1204a4883310d23cb6f6336fd05792e Mon Sep 17 00:00:00 2001 From: CJ Kindel Date: Wed, 25 Sep 2024 12:04:40 -0700 Subject: [PATCH 7/8] Add Griptape Cloud S3 Data Connector documentation (#1201) --- docs/griptape-cloud/data-sources/create-data-source.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/griptape-cloud/data-sources/create-data-source.md b/docs/griptape-cloud/data-sources/create-data-source.md index 347f527257..87a5286a03 100644 --- a/docs/griptape-cloud/data-sources/create-data-source.md +++ b/docs/griptape-cloud/data-sources/create-data-source.md @@ -10,6 +10,10 @@ You can [create a Data Source in the Griptape Cloud console](https://cloud.gript You can scrape and ingest a single, public web page by providing a URL. If you wish to scrape multiple pages, you must create multiple Data Sources. However, you can then add all of the pages to the same Knowledge Base if you wish to access all the pages together. +### Amazon S3 + +You can connect Amazon S3 buckets, objects, and prefixes by providing their S3 URI(s). Supported file extensions include .pdf, .csv, .md, and most text-based file types. + ### Google Drive You can ingest documents and spreadsheets stored in a Google Drive account. We support all standard file formats such as text, markdown, spreadsheets, and presentations. From 53bc38b5162ef927127a7f838d2c74c88cc0919d Mon Sep 17 00:00:00 2001 From: Collin Dutter Date: Wed, 25 Sep 2024 14:51:57 -0700 Subject: [PATCH 8/8] Feature/workflow improvements (#1191) --- CHANGELOG.md | 4 ++ griptape/structures/agent.py | 6 +-- griptape/structures/pipeline.py | 4 +- griptape/structures/structure.py | 31 ++++++++++--- griptape/structures/workflow.py | 12 ++++- tests/unit/structures/test_agent.py | 13 ++---- tests/unit/structures/test_pipeline.py | 18 +++++++- tests/unit/structures/test_workflow.py | 63 ++++++++++++++++++++++++++ 8 files changed, 128 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f470f02e8..9391b50e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +### Added +- `Workflow.input_tasks` and `Workflow.output_tasks` to access the input and output tasks of a Workflow. +- Ability to pass nested list of `Tasks` to `Structure.tasks` allowing for more complex declarative Structure definitions. + ## Added - Parameter `pipeline_task` on `HuggingFacePipelinePromptDriver` for creating different types of `Pipeline`s. diff --git a/griptape/structures/agent.py b/griptape/structures/agent.py index 24f57395c6..ff73d5ee81 100644 --- a/griptape/structures/agent.py +++ b/griptape/structures/agent.py @@ -60,15 +60,15 @@ def task(self) -> BaseTask: return self.tasks[0] def add_task(self, task: BaseTask) -> BaseTask: - self.tasks.clear() + self._tasks.clear() task.preprocess(self) - self.tasks.append(task) + self._tasks.append(task) return task - def add_tasks(self, *tasks: BaseTask) -> list[BaseTask]: + def add_tasks(self, *tasks: BaseTask | list[BaseTask]) -> list[BaseTask]: if len(tasks) > 1: raise ValueError("Agents can only have one task.") return super().add_tasks(*tasks) diff --git a/griptape/structures/pipeline.py b/griptape/structures/pipeline.py index e89d838185..70e546d682 100644 --- a/griptape/structures/pipeline.py +++ b/griptape/structures/pipeline.py @@ -25,7 +25,7 @@ def add_task(self, task: BaseTask) -> BaseTask: self.output_task.child_ids.append(task.id) task.parent_ids.append(self.output_task.id) - self.tasks.append(task) + self._tasks.append(task) return task @@ -45,7 +45,7 @@ def insert_task(self, parent_task: BaseTask, task: BaseTask) -> BaseTask: parent_task.child_ids.append(task.id) parent_index = self.tasks.index(parent_task) - self.tasks.insert(parent_index + 1, task) + self._tasks.insert(parent_index + 1, task) return task diff --git a/griptape/structures/structure.py b/griptape/structures/structure.py index b066c336e7..1f6c3faaba 100644 --- a/griptape/structures/structure.py +++ b/griptape/structures/structure.py @@ -24,7 +24,7 @@ class Structure(ABC): id: str = field(default=Factory(lambda: uuid.uuid4().hex), kw_only=True) rulesets: list[Ruleset] = field(factory=list, kw_only=True) rules: list[BaseRule] = field(factory=list, kw_only=True) - tasks: list[BaseTask] = field(factory=list, kw_only=True) + _tasks: list[BaseTask | list[BaseTask]] = field(factory=list, kw_only=True, alias="tasks") conversation_memory: Optional[BaseConversationMemory] = field( default=Factory(lambda: ConversationMemory()), kw_only=True, @@ -54,12 +54,23 @@ def validate_rules(self, _: Attribute, rules: list[Rule]) -> None: raise ValueError("can't have both rules and rulesets specified") def __attrs_post_init__(self) -> None: - tasks = self.tasks.copy() - self.tasks.clear() + tasks = self._tasks.copy() + self._tasks.clear() self.add_tasks(*tasks) - def __add__(self, other: BaseTask | list[BaseTask]) -> list[BaseTask]: - return self.add_tasks(*other) if isinstance(other, list) else self + [other] + def __add__(self, other: BaseTask | list[BaseTask | list[BaseTask]]) -> list[BaseTask]: + return self.add_tasks(*other) if isinstance(other, list) else self.add_tasks(other) + + @property + def tasks(self) -> list[BaseTask]: + tasks = [] + + for task in self._tasks: + if isinstance(task, list): + tasks.extend(task) + else: + tasks.append(task) + return tasks @property def execution_args(self) -> tuple: @@ -98,8 +109,14 @@ def try_find_task(self, task_id: str) -> Optional[BaseTask]: return task return None - def add_tasks(self, *tasks: BaseTask) -> list[BaseTask]: - return [self.add_task(s) for s in tasks] + def add_tasks(self, *tasks: BaseTask | list[BaseTask]) -> list[BaseTask]: + added_tasks = [] + for task in tasks: + if isinstance(task, list): + added_tasks.extend(self.add_tasks(*task)) + else: + added_tasks.append(self.add_task(task)) + return added_tasks def context(self, task: BaseTask) -> dict[str, Any]: return {"args": self.execution_args, "structure": self} diff --git a/griptape/structures/workflow.py b/griptape/structures/workflow.py index cd7bef07d7..507f9f5db4 100644 --- a/griptape/structures/workflow.py +++ b/griptape/structures/workflow.py @@ -26,13 +26,21 @@ def input_task(self) -> Optional[BaseTask]: def output_task(self) -> Optional[BaseTask]: return self.order_tasks()[-1] if self.tasks else None + @property + def input_tasks(self) -> list[BaseTask]: + return [task for task in self.tasks if not task.parents] + + @property + def output_tasks(self) -> list[BaseTask]: + return [task for task in self.tasks if not task.children] + def add_task(self, task: BaseTask) -> BaseTask: if (existing_task := self.try_find_task(task.id)) is not None: return existing_task task.preprocess(self) - self.tasks.append(task) + self._tasks.append(task) return task @@ -82,7 +90,7 @@ def insert_task( last_parent_index = self.__link_task_to_parents(task, parent_tasks) # Insert the new task once, just after the last parent task - self.tasks.insert(last_parent_index + 1, task) + self._tasks.insert(last_parent_index + 1, task) return task diff --git a/tests/unit/structures/test_agent.py b/tests/unit/structures/test_agent.py index 235363bbe7..1b9fa4157b 100644 --- a/tests/unit/structures/test_agent.py +++ b/tests/unit/structures/test_agent.py @@ -133,17 +133,14 @@ def test_add_tasks(self): agent = Agent(prompt_driver=MockPromptDriver()) - try: + with pytest.raises(ValueError): agent.add_tasks(first_task, second_task) - raise AssertionError() - except ValueError: - assert True - try: + with pytest.raises(ValueError): agent + [first_task, second_task] - raise AssertionError() - except ValueError: - assert True + + with pytest.raises(ValueError): + agent.add_tasks([first_task, second_task]) def test_prompt_stack_without_memory(self): agent = Agent(prompt_driver=MockPromptDriver(), conversation_memory=None, rules=[Rule("test")]) diff --git a/tests/unit/structures/test_pipeline.py b/tests/unit/structures/test_pipeline.py index a7f7f40c11..7e9933d7b9 100644 --- a/tests/unit/structures/test_pipeline.py +++ b/tests/unit/structures/test_pipeline.py @@ -203,6 +203,22 @@ def test_add_tasks(self): assert len(second_task.parents) == 1 assert len(second_task.children) == 0 + def test_nested_tasks(self): + pipeline = Pipeline( + tasks=[ + [ + PromptTask("parent", id=f"parent_{i}"), + PromptTask("child", id=f"child_{i}", parent_ids=[f"parent_{i}"]), + PromptTask("grandchild", id=f"grandchild_{i}", parent_ids=[f"child_{i}"]), + ] + for i in range(3) + ] + ) + + pipeline.run() + assert pipeline.output_task.id == "grandchild_2" + assert len(pipeline.tasks) == 9 + def test_insert_task_in_middle(self): first_task = PromptTask("test1", id="test1") second_task = PromptTask("test2", id="test2") @@ -374,7 +390,7 @@ def test_add_duplicate_task_directly(self): pipeline = Pipeline() pipeline + task - pipeline.tasks.append(task) + pipeline._tasks.append(task) with pytest.raises(ValueError, match=f"Duplicate task with id {task.id} found."): pipeline.run() diff --git a/tests/unit/structures/test_workflow.py b/tests/unit/structures/test_workflow.py index 45610bf209..33b18e4738 100644 --- a/tests/unit/structures/test_workflow.py +++ b/tests/unit/structures/test_workflow.py @@ -762,6 +762,69 @@ def test_run_with_error_artifact_no_fail_fast(self, error_artifact_task, waiting assert workflow.output is not None + def test_nested_tasks(self): + workflow = Workflow( + tasks=[ + [ + PromptTask("parent", id=f"parent_{i}"), + PromptTask("child", id=f"child_{i}", parent_ids=[f"parent_{i}"]), + PromptTask("grandchild", id=f"grandchild_{i}", parent_ids=[f"child_{i}"]), + ] + for i in range(3) + ], + ) + + workflow.run() + + output_ids = [task.id for task in workflow.output_tasks] + assert output_ids == ["grandchild_0", "grandchild_1", "grandchild_2"] + assert len(workflow.tasks) == 9 + + def test_nested_tasks_property(self): + workflow = Workflow() + workflow._tasks = [ + [ + PromptTask("parent", id=f"parent_{i}"), + PromptTask("child", id=f"child_{i}", parent_ids=[f"parent_{i}"]), + PromptTask("grandchild", id=f"grandchild_{i}", parent_ids=[f"child_{i}"]), + ] + for i in range(3) + ] + + assert len(workflow.tasks) == 9 + + def test_output_tasks(self): + parent = PromptTask("parent") + child = PromptTask("child") + grandchild = PromptTask("grandchild") + workflow = Workflow( + tasks=[ + [parent, child, grandchild], + ] + ) + + workflow + parent + parent.add_child(child) + child.add_child(grandchild) + + assert workflow.output_tasks == [grandchild] + + def test_input_tasks(self): + parent = PromptTask("parent") + child = PromptTask("child") + grandchild = PromptTask("grandchild") + workflow = Workflow( + tasks=[ + [parent, child, grandchild], + ] + ) + + workflow + parent + parent.add_child(child) + child.add_child(grandchild) + + assert workflow.input_tasks == [parent] + @staticmethod def _validate_topology_1(workflow) -> None: assert len(workflow.tasks) == 4