diff --git a/CHANGELOG.md b/CHANGELOG.md index ee509ad8..004a5485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,31 @@ # CHANGELOG +## v0.11.0 (2025-01-02) + +### Chores + +- Targeting python 3.12 in CI ([#281](https://github.com/canvas-medical/canvas-plugins/pull/281), + [`c2ec60c`](https://github.com/canvas-medical/canvas-plugins/commit/c2ec60ce753e78ef9a5a40ede60ad4ebcce94da3)) + +### Features + +- Adds surescripts effect types and classes + ([#246](https://github.com/canvas-medical/canvas-plugins/pull/246), + [`500f38f`](https://github.com/canvas-medical/canvas-plugins/commit/500f38f14e824271170c785222649cc652033a56)) + +- Refactor ProtocolBaseHandler and add target_type to Events + ([#236](https://github.com/canvas-medical/canvas-plugins/pull/236), + [`d90dcd8`](https://github.com/canvas-medical/canvas-plugins/commit/d90dcd87f5329f49018d1802e4229c6698de7555)) + + ## v0.10.2 (2024-12-21) ### Bug Fixes -- Upgrade Python to 3.12 to match GitHub's runners - ([`9d42b25`](https://github.com/canvas-medical/canvas-plugins/commit/9d42b25d5b8e85d3bf430702b2896f866f535d2f)) +- Ignore hidden folders, hidden files and symlinks when building a plugin package + ([#242](https://github.com/canvas-medical/canvas-plugins/pull/242), + [`cbd96fa`](https://github.com/canvas-medical/canvas-plugins/commit/cbd96fa024f126fe99f93a528d590c8eae71c401)) - Improve error handling for canvas_cli install ([#267](https://github.com/canvas-medical/canvas-plugins/pull/267), @@ -16,23 +35,25 @@ ([#241](https://github.com/canvas-medical/canvas-plugins/pull/241), [`2c3c749`](https://github.com/canvas-medical/canvas-plugins/commit/2c3c749d4d68fb7e4a01d8a9a857c28519d513ad)) -- Ignore hidden folders, hidden files and symlinks when building a plugin package - ([#242](https://github.com/canvas-medical/canvas-plugins/pull/242), - [`cbd96fa`](https://github.com/canvas-medical/canvas-plugins/commit/cbd96fa024f126fe99f93a528d590c8eae71c401)) +- Upgrade Python to 3.12 to match GitHub's runners + ([`9d42b25`](https://github.com/canvas-medical/canvas-plugins/commit/9d42b25d5b8e85d3bf430702b2896f866f535d2f)) ### Chores -- Bump protobuf from 4.25.5 to 5.29.1 - ([#228](https://github.com/canvas-medical/canvas-plugins/pull/228), - [`3b5c69b`](https://github.com/canvas-medical/canvas-plugins/commit/3b5c69bf4b5a6ed00b8e5733cf520eedb4be4cd7)) +- Auto-update pre-commit hooks ([#231](https://github.com/canvas-medical/canvas-plugins/pull/231), + [`ffc2a76`](https://github.com/canvas-medical/canvas-plugins/commit/ffc2a761d48e3d87dca9677719635cc5f36ae68a)) - Bump ipython from 8.29.0 to 8.30.0 ([#255](https://github.com/canvas-medical/canvas-plugins/pull/255), [`5dbdc3d`](https://github.com/canvas-medical/canvas-plugins/commit/5dbdc3dbb05481ac53832197a78745e782de831b)) -- Bump typer from 0.13.1 to 0.15.1 - ([#256](https://github.com/canvas-medical/canvas-plugins/pull/256), - [`561a226`](https://github.com/canvas-medical/canvas-plugins/commit/561a226b0e8bb7cf989ce1c23aa8245aeda09ecf)) +- Bump protobuf from 4.25.5 to 5.29.1 + ([#228](https://github.com/canvas-medical/canvas-plugins/pull/228), + [`3b5c69b`](https://github.com/canvas-medical/canvas-plugins/commit/3b5c69bf4b5a6ed00b8e5733cf520eedb4be4cd7)) + +- Bump pydantic from 2.9.2 to 2.10.3 + ([#227](https://github.com/canvas-medical/canvas-plugins/pull/227), + [`1ecb6e2`](https://github.com/canvas-medical/canvas-plugins/commit/1ecb6e2dcb0169d63aaafe272758bb6280f59ee3)) - Bump the development-minors group with 3 updates ([#254](https://github.com/canvas-medical/canvas-plugins/pull/254), @@ -42,17 +63,14 @@ ([#253](https://github.com/canvas-medical/canvas-plugins/pull/253), [`7d0cc70`](https://github.com/canvas-medical/canvas-plugins/commit/7d0cc70122d182cc2f2ac63145e6a13f30b81c7e)) -- Auto-update pre-commit hooks ([#231](https://github.com/canvas-medical/canvas-plugins/pull/231), - [`ffc2a76`](https://github.com/canvas-medical/canvas-plugins/commit/ffc2a761d48e3d87dca9677719635cc5f36ae68a)) - -- Bump pydantic from 2.9.2 to 2.10.3 - ([#227](https://github.com/canvas-medical/canvas-plugins/pull/227), - [`1ecb6e2`](https://github.com/canvas-medical/canvas-plugins/commit/1ecb6e2dcb0169d63aaafe272758bb6280f59ee3)) - - Bump the production-patches group across 1 directory with 4 updates ([#235](https://github.com/canvas-medical/canvas-plugins/pull/235), [`768baf5`](https://github.com/canvas-medical/canvas-plugins/commit/768baf53567d786b86f5c8cd24fa4d46280fa70c)) +- Bump typer from 0.13.1 to 0.15.1 + ([#256](https://github.com/canvas-medical/canvas-plugins/pull/256), + [`561a226`](https://github.com/canvas-medical/canvas-plugins/commit/561a226b0e8bb7cf989ce1c23aa8245aeda09ecf)) + ## v0.10.1 (2024-12-12) @@ -73,14 +91,14 @@ ### Features -- Add patient profile section event and effect - ([#212](https://github.com/canvas-medical/canvas-plugins/pull/212), - [`f784d8f`](https://github.com/canvas-medical/canvas-plugins/commit/f784d8fa69244142685f2420bc3f6d0416bdd3e8)) - - Add events and effects for preferred pharmacies search ([#220](https://github.com/canvas-medical/canvas-plugins/pull/220), [`f9c41b8`](https://github.com/canvas-medical/canvas-plugins/commit/f9c41b84421896afab79d08f1176abdddca305b7)) +- Add patient profile section event and effect + ([#212](https://github.com/canvas-medical/canvas-plugins/pull/212), + [`f784d8f`](https://github.com/canvas-medical/canvas-plugins/commit/f784d8fa69244142685f2420bc3f6d0416bdd3e8)) + ## v0.9.0 (2024-12-05) @@ -111,10 +129,6 @@ Signed-off-by: Christopher Sande ### Chores -- Update dependencies for Python 3.12 support - ([#226](https://github.com/canvas-medical/canvas-plugins/pull/226), - [`d637bc6`](https://github.com/canvas-medical/canvas-plugins/commit/d637bc661e576ba550f57e76a9428fc8456b0522)) - - Auto-update pre-commit hooks ([#200](https://github.com/canvas-medical/canvas-plugins/pull/200), [`c422a3f`](https://github.com/canvas-medical/canvas-plugins/commit/c422a3fda7f5bda5c1623c97f1afd40ef793596c)) @@ -122,6 +136,10 @@ Signed-off-by: Christopher Sande ([#216](https://github.com/canvas-medical/canvas-plugins/pull/216), [`15d2809`](https://github.com/canvas-medical/canvas-plugins/commit/15d2809339da704976213cbe448e7221120422de)) +- Update dependencies for Python 3.12 support + ([#226](https://github.com/canvas-medical/canvas-plugins/pull/226), + [`d637bc6`](https://github.com/canvas-medical/canvas-plugins/commit/d637bc661e576ba550f57e76a9428fc8456b0522)) + ## v0.8.0 (2024-12-03) @@ -150,25 +168,30 @@ Signed-off-by: Christopher Sande ### Features -- Moves task effects ([#208](https://github.com/canvas-medical/canvas-plugins/pull/208), - [`ea80d80`](https://github.com/canvas-medical/canvas-plugins/commit/ea80d804a36b0aab5249cf42670b2d773236b1aa)) +- Add models for task, task labels, task comments and staff + ([#202](https://github.com/canvas-medical/canvas-plugins/pull/202), + [`0fc5590`](https://github.com/canvas-medical/canvas-plugins/commit/0fc55901111d770bad6de5d1f6bdc160c33d7b5c)) - Adds TASK_CLOSED and TASK_COMPLETED events ([#205](https://github.com/canvas-medical/canvas-plugins/pull/205), [`062786a`](https://github.com/canvas-medical/canvas-plugins/commit/062786aaa498b8cc9f5b4e4bd17c39d4d31bb039)) +- Moves task effects ([#208](https://github.com/canvas-medical/canvas-plugins/pull/208), + [`ea80d80`](https://github.com/canvas-medical/canvas-plugins/commit/ea80d804a36b0aab5249cf42670b2d773236b1aa)) + - Plugins functionality for protocol conversions ([#183](https://github.com/canvas-medical/canvas-plugins/pull/183), [`69e95c8`](https://github.com/canvas-medical/canvas-plugins/commit/69e95c8894c051f06a9fd60e05704cbf24edf48a)) -Signed-off-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> Co-authored-by: - Christopher Sande Co-authored-by: José Magalhães - Co-authored-by: Michela Iannaccone - Co-authored-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> +Signed-off-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> -- Add models for task, task labels, task comments and staff - ([#202](https://github.com/canvas-medical/canvas-plugins/pull/202), - [`0fc5590`](https://github.com/canvas-medical/canvas-plugins/commit/0fc55901111d770bad6de5d1f6bdc160c33d7b5c)) +Co-authored-by: Christopher Sande + +Co-authored-by: José Magalhães + +Co-authored-by: Michela Iannaccone + +Co-authored-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> ## v0.6.0 (2024-11-21) @@ -202,43 +225,43 @@ Signed-off-by: Christopher Sande ### Chores -- Bump aiohttp from 3.10.5 to 3.10.11 - ([#197](https://github.com/canvas-medical/canvas-plugins/pull/197), - [`cc2138a`](https://github.com/canvas-medical/canvas-plugins/commit/cc2138ac32b8691567d820263f5d0baa18cacd4d)) - - Auto-update pre-commit hooks ([#198](https://github.com/canvas-medical/canvas-plugins/pull/198), [`a4046a7`](https://github.com/canvas-medical/canvas-plugins/commit/a4046a7a251061a9ead37c22ce53983530ebd8dd)) -- Bump typer from 0.13.0 to 0.13.1 in the production-patches group - ([#199](https://github.com/canvas-medical/canvas-plugins/pull/199), - [`93ddd99`](https://github.com/canvas-medical/canvas-plugins/commit/93ddd99ea0faa9760e0b4302ff321fded17625c6)) +- Bump aiohttp from 3.10.5 to 3.10.11 + ([#197](https://github.com/canvas-medical/canvas-plugins/pull/197), + [`cc2138a`](https://github.com/canvas-medical/canvas-plugins/commit/cc2138ac32b8691567d820263f5d0baa18cacd4d)) -- Bump typer from 0.12.5 to 0.13.0 - ([#185](https://github.com/canvas-medical/canvas-plugins/pull/185), - [`170fdf8`](https://github.com/canvas-medical/canvas-plugins/commit/170fdf8408c03273dee802940add5a321c45cfa8)) +- Bump grpcio from 1.67.1 to 1.68.0 + ([#196](https://github.com/canvas-medical/canvas-plugins/pull/196), + [`4980319`](https://github.com/canvas-medical/canvas-plugins/commit/498031977fd5a07d87ee83601b87ab35c6b79165)) - Bump pyjwt from 2.9.0 to 2.10.0 ([#195](https://github.com/canvas-medical/canvas-plugins/pull/195), [`6417714`](https://github.com/canvas-medical/canvas-plugins/commit/641771461c230799e15737bc9dab7369d4e49d8c)) -- Bump grpcio from 1.67.1 to 1.68.0 - ([#196](https://github.com/canvas-medical/canvas-plugins/pull/196), - [`4980319`](https://github.com/canvas-medical/canvas-plugins/commit/498031977fd5a07d87ee83601b87ab35c6b79165)) - - Bump python-semantic-release from 9.12.1 to 9.14.0 in the development-minors group ([#189](https://github.com/canvas-medical/canvas-plugins/pull/189), [`bf236a7`](https://github.com/canvas-medical/canvas-plugins/commit/bf236a7b3fe75643dbcf9d14b0fc9d2cebf9bfdb)) -### Features +- Bump typer from 0.12.5 to 0.13.0 + ([#185](https://github.com/canvas-medical/canvas-plugins/pull/185), + [`170fdf8`](https://github.com/canvas-medical/canvas-plugins/commit/170fdf8408c03273dee802940add5a321c45cfa8)) -- Add coding gaps to patient chart configuration effect - ([#186](https://github.com/canvas-medical/canvas-plugins/pull/186), - [`a32bf18`](https://github.com/canvas-medical/canvas-plugins/commit/a32bf18f3f975621f3e2ba32834c2252e4509b46)) +- Bump typer from 0.13.0 to 0.13.1 in the production-patches group + ([#199](https://github.com/canvas-medical/canvas-plugins/pull/199), + [`93ddd99`](https://github.com/canvas-medical/canvas-plugins/commit/93ddd99ea0faa9760e0b4302ff321fded17625c6)) + +### Features - Add capabilities for coding gap related plugins ([#191](https://github.com/canvas-medical/canvas-plugins/pull/191), [`45bf543`](https://github.com/canvas-medical/canvas-plugins/commit/45bf543e09bd53d4c8cb06f5cd522eae74e0dba7)) +- Add coding gaps to patient chart configuration effect + ([#186](https://github.com/canvas-medical/canvas-plugins/pull/186), + [`a32bf18`](https://github.com/canvas-medical/canvas-plugins/commit/a32bf18f3f975621f3e2ba32834c2252e4509b46)) + - Data module model for ProtocolOverride ([#149](https://github.com/canvas-medical/canvas-plugins/pull/149), [`0556717`](https://github.com/canvas-medical/canvas-plugins/commit/055671730410fc01110452346c5f6763db1d4aea)) @@ -254,17 +277,17 @@ Signed-off-by: Christopher Sande ### Chores -- Improve mypy configuration and fix the resulting errors - ([#187](https://github.com/canvas-medical/canvas-plugins/pull/187), - [`44071f1`](https://github.com/canvas-medical/canvas-plugins/commit/44071f13f069027d1d1fdadc932fe167010591ac)) +- Bump django from 5.1.2 to 5.1.3 in the production-patches group + ([#179](https://github.com/canvas-medical/canvas-plugins/pull/179), + [`163540a`](https://github.com/canvas-medical/canvas-plugins/commit/163540a7b833e52f5fa50a17f595fda1e1adaa63)) - Bump the development-patches group across 1 directory with 2 updates ([#182](https://github.com/canvas-medical/canvas-plugins/pull/182), [`babb355`](https://github.com/canvas-medical/canvas-plugins/commit/babb3556ef487fb546319e526fca519ea6c6dbd8)) -- Bump django from 5.1.2 to 5.1.3 in the production-patches group - ([#179](https://github.com/canvas-medical/canvas-plugins/pull/179), - [`163540a`](https://github.com/canvas-medical/canvas-plugins/commit/163540a7b833e52f5fa50a17f595fda1e1adaa63)) +- Improve mypy configuration and fix the resulting errors + ([#187](https://github.com/canvas-medical/canvas-plugins/pull/187), + [`44071f1`](https://github.com/canvas-medical/canvas-plugins/commit/44071f13f069027d1d1fdadc932fe167010591ac)) ### Code Style @@ -274,22 +297,23 @@ Signed-off-by: Christopher Sande ### Features -- Adds more lab related models ([#130](https://github.com/canvas-medical/canvas-plugins/pull/130), - [`6177e00`](https://github.com/canvas-medical/canvas-plugins/commit/6177e00a32f24e314c80aa6223249a341a745835)) +- Add is_predictive property to cqm class meta + ([#181](https://github.com/canvas-medical/canvas-plugins/pull/181), + [`9ff3117`](https://github.com/canvas-medical/canvas-plugins/commit/9ff3117a0758d17d7381e39721dcbdbc7ea12f12)) -Signed-off-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> Co-authored-by: - Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> +- Add plugin_created and plugin_updated events + ([#178](https://github.com/canvas-medical/canvas-plugins/pull/178), + [`efd45e2`](https://github.com/canvas-medical/canvas-plugins/commit/efd45e281e6d63ba0c8865e92e5521186df476b3)) - Adds imaging models ([#137](https://github.com/canvas-medical/canvas-plugins/pull/137), [`84c63e2`](https://github.com/canvas-medical/canvas-plugins/commit/84c63e2cb1225f1c481ea7b59d5fb2963afba08b)) -- Add plugin_created and plugin_updated events - ([#178](https://github.com/canvas-medical/canvas-plugins/pull/178), - [`efd45e2`](https://github.com/canvas-medical/canvas-plugins/commit/efd45e281e6d63ba0c8865e92e5521186df476b3)) +- Adds more lab related models ([#130](https://github.com/canvas-medical/canvas-plugins/pull/130), + [`6177e00`](https://github.com/canvas-medical/canvas-plugins/commit/6177e00a32f24e314c80aa6223249a341a745835)) -- Add is_predictive property to cqm class meta - ([#181](https://github.com/canvas-medical/canvas-plugins/pull/181), - [`9ff3117`](https://github.com/canvas-medical/canvas-plugins/commit/9ff3117a0758d17d7381e39721dcbdbc7ea12f12)) +Signed-off-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> + +Co-authored-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> ## v0.3.1 (2024-10-31) @@ -301,15 +325,15 @@ Signed-off-by: Kristen ONeill <91080969+kristenoneill@users.noreply.github.com> ### Chores +- Fix test distribution step on semantic release gh action + ([#173](https://github.com/canvas-medical/canvas-plugins/pull/173), + [`6ee6b0c`](https://github.com/canvas-medical/canvas-plugins/commit/6ee6b0c715b771072a9a81b91bc7cc7f7bcb16e7)) + - Local development improvements ([#102](https://github.com/canvas-medical/canvas-plugins/pull/102), [`ca4458e`](https://github.com/canvas-medical/canvas-plugins/commit/ca4458e59ee51abf638facb8eb9ff231be0efa18)) Co-authored-by: José Magalhães -- Fix test distribution step on semantic release gh action - ([#173](https://github.com/canvas-medical/canvas-plugins/pull/173), - [`6ee6b0c`](https://github.com/canvas-medical/canvas-plugins/commit/6ee6b0c715b771072a9a81b91bc7cc7f7bcb16e7)) - ## v0.3.0 (2024-10-29) @@ -321,116 +345,116 @@ Co-authored-by: José Magalhães ### Chores -- Bump keyring from 25.4.1 to 25.5.0 - ([#170](https://github.com/canvas-medical/canvas-plugins/pull/170), - [`c7ca11d`](https://github.com/canvas-medical/canvas-plugins/commit/c7ca11d5d262a2a1b4b9808ef0fef834b3523fd7)) - -- Bump grpcio-tools from 1.62.0 to 1.62.3 in the development-minors group - ([#168](https://github.com/canvas-medical/canvas-plugins/pull/168), - [`755f741`](https://github.com/canvas-medical/canvas-plugins/commit/755f741562b2bde3e69df44f85aeee1b90bd4290)) - -- Bump grpcio from 1.67.0 to 1.67.1 in the production-patches group - ([#172](https://github.com/canvas-medical/canvas-plugins/pull/172), - [`22c5bc3`](https://github.com/canvas-medical/canvas-plugins/commit/22c5bc33ac21b77e7b0854abeb5f2cc2dcb12ace)) +- Add dependabot config ([#150](https://github.com/canvas-medical/canvas-plugins/pull/150), + [`f8841fd`](https://github.com/canvas-medical/canvas-plugins/commit/f8841fdcae718da368a588c9630fa9844318aa5f)) -- Bump pydantic from 2.6.1 to 2.9.2 - ([#164](https://github.com/canvas-medical/canvas-plugins/pull/164), - [`14d4be1`](https://github.com/canvas-medical/canvas-plugins/commit/14d4be1ee7f4051eb7f7bb19bee15d5a7402674d)) +- Auto-update pre-commit hooks ([#142](https://github.com/canvas-medical/canvas-plugins/pull/142), + [`d4aff18`](https://github.com/canvas-medical/canvas-plugins/commit/d4aff18587a8802f0bd5fcf0f431586a533fd9f9)) -- Bump keyring from 24.3.0 to 25.4.1 - ([#157](https://github.com/canvas-medical/canvas-plugins/pull/157), - [`23327a5`](https://github.com/canvas-medical/canvas-plugins/commit/23327a5cab5621e9471aa1f2f0871946e8a44921)) +- Auto-update pre-commit hooks ([#146](https://github.com/canvas-medical/canvas-plugins/pull/146), + [`b0bfb46`](https://github.com/canvas-medical/canvas-plugins/commit/b0bfb46a14d5133894310641618fa3f97b45064e)) - Bump grpcio from 1.62.0 to 1.67.0 ([#165](https://github.com/canvas-medical/canvas-plugins/pull/165), [`030048d`](https://github.com/canvas-medical/canvas-plugins/commit/030048df188566822e2ce0f6de4ea0e354aec0ce)) -- Bump pyjwt from 2.4.0 to 2.9.0 ([#167](https://github.com/canvas-medical/canvas-plugins/pull/167), - [`594dc74`](https://github.com/canvas-medical/canvas-plugins/commit/594dc74ca88244307a6e43230ad9a75ec57dfc43)) +- Bump grpcio from 1.67.0 to 1.67.1 in the production-patches group + ([#172](https://github.com/canvas-medical/canvas-plugins/pull/172), + [`22c5bc3`](https://github.com/canvas-medical/canvas-plugins/commit/22c5bc33ac21b77e7b0854abeb5f2cc2dcb12ace)) + +- Bump grpcio-tools from 1.62.0 to 1.62.3 in the development-minors group + ([#168](https://github.com/canvas-medical/canvas-plugins/pull/168), + [`755f741`](https://github.com/canvas-medical/canvas-plugins/commit/755f741562b2bde3e69df44f85aeee1b90bd4290)) - Bump ipython from 8.21.0 to 8.29.0 ([#159](https://github.com/canvas-medical/canvas-plugins/pull/159), [`54d2651`](https://github.com/canvas-medical/canvas-plugins/commit/54d265186e2cc679fdbc240dd7405964c594673c)) -- Auto-update pre-commit hooks ([#146](https://github.com/canvas-medical/canvas-plugins/pull/146), - [`b0bfb46`](https://github.com/canvas-medical/canvas-plugins/commit/b0bfb46a14d5133894310641618fa3f97b45064e)) +- Bump jsonschema from 4.21.1 to 4.23.0 + ([#163](https://github.com/canvas-medical/canvas-plugins/pull/163), + [`5be8644`](https://github.com/canvas-medical/canvas-plugins/commit/5be8644a9a0befbcc7806be5b424164b51f366ad)) -- Bump typer from 0.9.0 to 0.12.5 - ([#162](https://github.com/canvas-medical/canvas-plugins/pull/162), - [`cb6af5c`](https://github.com/canvas-medical/canvas-plugins/commit/cb6af5c3a76a1326388604edd62e82186a0ee888)) +- Bump keyring from 24.3.0 to 25.4.1 + ([#157](https://github.com/canvas-medical/canvas-plugins/pull/157), + [`23327a5`](https://github.com/canvas-medical/canvas-plugins/commit/23327a5cab5621e9471aa1f2f0871946e8a44921)) -- Bump restrictedpython from 7.3 to 7.4 - ([#166](https://github.com/canvas-medical/canvas-plugins/pull/166), - [`1acb504`](https://github.com/canvas-medical/canvas-plugins/commit/1acb504469b0c6ae99f3ae3d2f41eacefeb3a80a)) +- Bump keyring from 25.4.1 to 25.5.0 + ([#170](https://github.com/canvas-medical/canvas-plugins/pull/170), + [`c7ca11d`](https://github.com/canvas-medical/canvas-plugins/commit/c7ca11d5d262a2a1b4b9808ef0fef834b3523fd7)) -- Bump redis from 5.0.4 to 5.2.0 ([#161](https://github.com/canvas-medical/canvas-plugins/pull/161), - [`fe40619`](https://github.com/canvas-medical/canvas-plugins/commit/fe4061918e49173a7aecb8a7312f7f39e064005c)) +- Bump peter-evans/create-pull-request from 4 to 7 + ([#151](https://github.com/canvas-medical/canvas-plugins/pull/151), + [`47e6c8f`](https://github.com/canvas-medical/canvas-plugins/commit/47e6c8f96cb535f0aa81fd976a108e02d7c8182b)) -- Bump typing-extensions from 4.8.0 to 4.12.2 - ([#158](https://github.com/canvas-medical/canvas-plugins/pull/158), - [`47c4add`](https://github.com/canvas-medical/canvas-plugins/commit/47c4add0920124dabbdddff43bbb253cd15281d2)) +- Bump pre-commit from 3.6.2 to 4.0.1 in the development-majors group + ([#155](https://github.com/canvas-medical/canvas-plugins/pull/155), + [`6eb777b`](https://github.com/canvas-medical/canvas-plugins/commit/6eb777b695edd79f291a763d5466a7b22316cf07)) + +- Bump pre-commit/action from 3.0.0 to 3.0.1 + ([#152](https://github.com/canvas-medical/canvas-plugins/pull/152), + [`3bd3919`](https://github.com/canvas-medical/canvas-plugins/commit/3bd39191efcab214634fbb5b06440d45ff63c8cb)) - Bump protobuf from 4.25.3 to 4.25.5 ([#156](https://github.com/canvas-medical/canvas-plugins/pull/156), [`85e23dd`](https://github.com/canvas-medical/canvas-plugins/commit/85e23dd61247ad1db45b82f4a8db48ddbabeae87)) -- Bump jsonschema from 4.21.1 to 4.23.0 - ([#163](https://github.com/canvas-medical/canvas-plugins/pull/163), - [`5be8644`](https://github.com/canvas-medical/canvas-plugins/commit/5be8644a9a0befbcc7806be5b424164b51f366ad)) +- Bump pydantic from 2.6.1 to 2.9.2 + ([#164](https://github.com/canvas-medical/canvas-plugins/pull/164), + [`14d4be1`](https://github.com/canvas-medical/canvas-plugins/commit/14d4be1ee7f4051eb7f7bb19bee15d5a7402674d)) -- Bump websocket-client from 1.7.0 to 1.8.0 - ([#160](https://github.com/canvas-medical/canvas-plugins/pull/160), - [`28b4389`](https://github.com/canvas-medical/canvas-plugins/commit/28b43891394312fd92af84d86e49f1a2095708a3)) +- Bump pyjwt from 2.4.0 to 2.9.0 ([#167](https://github.com/canvas-medical/canvas-plugins/pull/167), + [`594dc74`](https://github.com/canvas-medical/canvas-plugins/commit/594dc74ca88244307a6e43230ad9a75ec57dfc43)) + +- Bump redis from 5.0.4 to 5.2.0 ([#161](https://github.com/canvas-medical/canvas-plugins/pull/161), + [`fe40619`](https://github.com/canvas-medical/canvas-plugins/commit/fe4061918e49173a7aecb8a7312f7f39e064005c)) + +- Bump restrictedpython from 7.3 to 7.4 + ([#166](https://github.com/canvas-medical/canvas-plugins/pull/166), + [`1acb504`](https://github.com/canvas-medical/canvas-plugins/commit/1acb504469b0c6ae99f3ae3d2f41eacefeb3a80a)) - Bump the development-minors group with 8 updates ([#154](https://github.com/canvas-medical/canvas-plugins/pull/154), [`24b4d9a`](https://github.com/canvas-medical/canvas-plugins/commit/24b4d9aaee3209e60266caf973e2ac6a28369f09)) -- Bump peter-evans/create-pull-request from 4 to 7 - ([#151](https://github.com/canvas-medical/canvas-plugins/pull/151), - [`47e6c8f`](https://github.com/canvas-medical/canvas-plugins/commit/47e6c8f96cb535f0aa81fd976a108e02d7c8182b)) - - Bump the production-patches group with 3 updates ([#153](https://github.com/canvas-medical/canvas-plugins/pull/153), [`9f3e69a`](https://github.com/canvas-medical/canvas-plugins/commit/9f3e69a79e46672a65830af3f0adac2703dc1191)) -- Bump pre-commit/action from 3.0.0 to 3.0.1 - ([#152](https://github.com/canvas-medical/canvas-plugins/pull/152), - [`3bd3919`](https://github.com/canvas-medical/canvas-plugins/commit/3bd39191efcab214634fbb5b06440d45ff63c8cb)) +- Bump typer from 0.9.0 to 0.12.5 + ([#162](https://github.com/canvas-medical/canvas-plugins/pull/162), + [`cb6af5c`](https://github.com/canvas-medical/canvas-plugins/commit/cb6af5c3a76a1326388604edd62e82186a0ee888)) -- Bump pre-commit from 3.6.2 to 4.0.1 in the development-majors group - ([#155](https://github.com/canvas-medical/canvas-plugins/pull/155), - [`6eb777b`](https://github.com/canvas-medical/canvas-plugins/commit/6eb777b695edd79f291a763d5466a7b22316cf07)) +- Bump typing-extensions from 4.8.0 to 4.12.2 + ([#158](https://github.com/canvas-medical/canvas-plugins/pull/158), + [`47c4add`](https://github.com/canvas-medical/canvas-plugins/commit/47c4add0920124dabbdddff43bbb253cd15281d2)) -- Add dependabot config ([#150](https://github.com/canvas-medical/canvas-plugins/pull/150), - [`f8841fd`](https://github.com/canvas-medical/canvas-plugins/commit/f8841fdcae718da368a588c9630fa9844318aa5f)) +- Bump websocket-client from 1.7.0 to 1.8.0 + ([#160](https://github.com/canvas-medical/canvas-plugins/pull/160), + [`28b4389`](https://github.com/canvas-medical/canvas-plugins/commit/28b43891394312fd92af84d86e49f1a2095708a3)) + +- Clean up pre-commit-update workflow + ([#141](https://github.com/canvas-medical/canvas-plugins/pull/141), + [`2ab0694`](https://github.com/canvas-medical/canvas-plugins/commit/2ab0694215d6463e3e556dd76ae4f2dbc50e597f)) - Enhance release process by installing and executing the distribution ([#143](https://github.com/canvas-medical/canvas-plugins/pull/143), [`2d2352d`](https://github.com/canvas-medical/canvas-plugins/commit/2d2352d7354599a6bad15a7820a8c1d217144a6a)) -- Auto-update pre-commit hooks ([#142](https://github.com/canvas-medical/canvas-plugins/pull/142), - [`d4aff18`](https://github.com/canvas-medical/canvas-plugins/commit/d4aff18587a8802f0bd5fcf0f431586a533fd9f9)) - -- Clean up pre-commit-update workflow - ([#141](https://github.com/canvas-medical/canvas-plugins/pull/141), - [`2ab0694`](https://github.com/canvas-medical/canvas-plugins/commit/2ab0694215d6463e3e556dd76ae4f2dbc50e597f)) +- Fix pre-commit errors ([#138](https://github.com/canvas-medical/canvas-plugins/pull/138), + [`1da3f33`](https://github.com/canvas-medical/canvas-plugins/commit/1da3f33adda53f73ec114075f1c581218f8e24ea)) - Improve generate-protobufs script ([#135](https://github.com/canvas-medical/canvas-plugins/pull/135), [`61597ab`](https://github.com/canvas-medical/canvas-plugins/commit/61597abea8cf16248c422657cbfa6632a056b396)) -- Fix pre-commit errors ([#138](https://github.com/canvas-medical/canvas-plugins/pull/138), - [`1da3f33`](https://github.com/canvas-medical/canvas-plugins/commit/1da3f33adda53f73ec114075f1c581218f8e24ea)) - - **ci**: Fix pre-commit on CI ([#136](https://github.com/canvas-medical/canvas-plugins/pull/136), [`ec6b4b3`](https://github.com/canvas-medical/canvas-plugins/commit/ec6b4b3849582bdfcfea9cb605d894b62c9d1bf7)) ### Features -- Add SDK Questionnaire and Interview models - ([#104](https://github.com/canvas-medical/canvas-plugins/pull/104), - [`ba8b556`](https://github.com/canvas-medical/canvas-plugins/commit/ba8b556ee1b36a173ab07ddd4d705d5b131c6fc7)) +- Add feedback_enabled property to protocol card effect + ([#148](https://github.com/canvas-medical/canvas-plugins/pull/148), + [`5dd7d96`](https://github.com/canvas-medical/canvas-plugins/commit/5dd7d963fd36a627c6072c8ead83e76eaa8ad950)) - Add more event types ([#139](https://github.com/canvas-medical/canvas-plugins/pull/139), [`ffc9c25`](https://github.com/canvas-medical/canvas-plugins/commit/ffc9c255181da5a95a0bd4e1535c988e40e39761)) @@ -439,9 +463,9 @@ Co-authored-by: José Magalhães ([#145](https://github.com/canvas-medical/canvas-plugins/pull/145), [`517cadb`](https://github.com/canvas-medical/canvas-plugins/commit/517cadb18fc09ded585b74975edc74283acb7040)) -- Add feedback_enabled property to protocol card effect - ([#148](https://github.com/canvas-medical/canvas-plugins/pull/148), - [`5dd7d96`](https://github.com/canvas-medical/canvas-plugins/commit/5dd7d963fd36a627c6072c8ead83e76eaa8ad950)) +- Add SDK Questionnaire and Interview models + ([#104](https://github.com/canvas-medical/canvas-plugins/pull/104), + [`ba8b556`](https://github.com/canvas-medical/canvas-plugins/commit/ba8b556ee1b36a173ab07ddd4d705d5b131c6fc7)) - Clipboard command events ([#147](https://github.com/canvas-medical/canvas-plugins/pull/147), [`eaf339a`](https://github.com/canvas-medical/canvas-plugins/commit/eaf339a1656978b04c16e4453d96c77c9ca868df)) @@ -464,15 +488,15 @@ Co-authored-by: José Magalhães - Fix semantic release workflow ([#134](https://github.com/canvas-medical/canvas-plugins/pull/134), [`97a5069`](https://github.com/canvas-medical/canvas-plugins/commit/97a5069d8eeda5c8f455c531feb5c1a40e4fb487)) +- Fix semantic-release publish ([#129](https://github.com/canvas-medical/canvas-plugins/pull/129), + [`8a24339`](https://github.com/canvas-medical/canvas-plugins/commit/8a24339455bb58246c78d2670b02465207991a4f)) + - **docs**: Add CONTRIBUTING.md and CODE_OF_CONDUCT.md ([#132](https://github.com/canvas-medical/canvas-plugins/pull/132), [`365751b`](https://github.com/canvas-medical/canvas-plugins/commit/365751b186d8d20454cf059b749f9ebdcd3ebd56)) chore(docs): add CONTRIBUTING and CODE_OF_CONDUCT -- Fix semantic-release publish ([#129](https://github.com/canvas-medical/canvas-plugins/pull/129), - [`8a24339`](https://github.com/canvas-medical/canvas-plugins/commit/8a24339455bb58246c78d2670b02465207991a4f)) - ## v0.2.10 (2024-10-14) @@ -483,12 +507,9 @@ chore(docs): add CONTRIBUTING and CODE_OF_CONDUCT ### Chores -- Fix semantic release ([#128](https://github.com/canvas-medical/canvas-plugins/pull/128), - [`d4bbcc7`](https://github.com/canvas-medical/canvas-plugins/commit/d4bbcc737f08cd528b09a71a23cc6deabc427d66)) - -- **ci**: Add automated releases using semantic release - ([#127](https://github.com/canvas-medical/canvas-plugins/pull/127), - [`2f830c8`](https://github.com/canvas-medical/canvas-plugins/commit/2f830c8cfb4436b34502d457456e97b487e9c122)) +- Add pull request title validator + ([#126](https://github.com/canvas-medical/canvas-plugins/pull/126), + [`194bf0b`](https://github.com/canvas-medical/canvas-plugins/commit/194bf0b56c5c036de853ed149a702eecf7ec3af5)) - Bump restrictedpython from 7.1 to 7.3 ([#117](https://github.com/canvas-medical/canvas-plugins/pull/117), @@ -500,14 +521,20 @@ Bumps [restrictedpython](https://github.com/zopefoundation/RestrictedPython) fro [Changelog](https://github.com/zopefoundation/RestrictedPython/blob/master/CHANGES.rst) - [Commits](https://github.com/zopefoundation/RestrictedPython/compare/7.1...7.3) ---- updated-dependencies: - dependency-name: restrictedpython dependency-type: direct:production ... +--- updated-dependencies: - dependency-name: restrictedpython dependency-type: direct:production -Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] - <49699333+dependabot[bot]@users.noreply.github.com> +... -- Add pull request title validator - ([#126](https://github.com/canvas-medical/canvas-plugins/pull/126), - [`194bf0b`](https://github.com/canvas-medical/canvas-plugins/commit/194bf0b56c5c036de853ed149a702eecf7ec3af5)) +Signed-off-by: dependabot[bot] + +Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> + +- Fix semantic release ([#128](https://github.com/canvas-medical/canvas-plugins/pull/128), + [`d4bbcc7`](https://github.com/canvas-medical/canvas-plugins/commit/d4bbcc737f08cd528b09a71a23cc6deabc427d66)) + +- **ci**: Add automated releases using semantic release + ([#127](https://github.com/canvas-medical/canvas-plugins/pull/127), + [`2f830c8`](https://github.com/canvas-medical/canvas-plugins/commit/2f830c8cfb4436b34502d457456e97b487e9c122)) - **ci**: Improve build and test workflow ([#125](https://github.com/canvas-medical/canvas-plugins/pull/125), @@ -518,12 +545,12 @@ Signed-off-by: dependabot[bot] Co-authored-by: dependabot[b ### Bug Fixes -- Improve AllergyCommand definition - ([`049c16d`](https://github.com/canvas-medical/canvas-plugins/commit/049c16dc00aba1c13726855c42f6de0797c2e49f)) - - Add MedicalHistoryCommand to __init__ ([`0b91465`](https://github.com/canvas-medical/canvas-plugins/commit/0b91465ada1dbbb1d3038d2e4aec07d2b8f85362)) +- Improve AllergyCommand definition + ([`049c16d`](https://github.com/canvas-medical/canvas-plugins/commit/049c16dc00aba1c13726855c42f6de0797c2e49f)) + ## v0.2.8 (2024-10-02) @@ -545,28 +572,31 @@ Signed-off-by: dependabot[bot] Co-authored-by: dependabot[b ### Chores -- Update protobufs - ([`549adaa`](https://github.com/canvas-medical/canvas-plugins/commit/549adaaef8a466e41d7be8e470ef1b9d015b0df9)) - - Add black ad dev dependency ([`4799bae`](https://github.com/canvas-medical/canvas-plugins/commit/4799bae667f2e99f1c557050781d86a491797c7f)) +- Update protobufs + ([`549adaa`](https://github.com/canvas-medical/canvas-plugins/commit/549adaaef8a466e41d7be8e470ef1b9d015b0df9)) + ### Features +- Add Allergy command SDK definition + ([`87f05cf`](https://github.com/canvas-medical/canvas-plugins/commit/87f05cf16813e267b9cba7c8c947cee171dd44fd)) + - Add CloseGoal command SDK definition ([`f99b86d`](https://github.com/canvas-medical/canvas-plugins/commit/f99b86d78498dcf16d04861d6674094b943c8165)) -- Add UpdateDiagnosis command SDK definition - ([`f751d07`](https://github.com/canvas-medical/canvas-plugins/commit/f751d074a4758a704c3de2ee4ba69470daf18f0b)) +- Add effects for Perform Command + ([`b379a28`](https://github.com/canvas-medical/canvas-plugins/commit/b379a289ac483ed1dcc1463b20bb7671aa43ba11)) -- Add Vitals command SDK definition - ([`ad56f11`](https://github.com/canvas-medical/canvas-plugins/commit/ad56f1193d58e73b9cf5aef81e9c5787b8879a8e)) +- Add FamilyHistory command SDK definition + ([`a77fa6d`](https://github.com/canvas-medical/canvas-plugins/commit/a77fa6dcb6f742827955da8c9afa7c1a83636480)) -- Add Refill command SDK definition - ([`36b3e1e`](https://github.com/canvas-medical/canvas-plugins/commit/36b3e1e6c259562fa66e9e3ddfdc1c138a087e75)) +- Add instruct and perform commands + ([`08997ed`](https://github.com/canvas-medical/canvas-plugins/commit/08997ed5f96bb2971eeed9a179704ffacaab6494)) -- Add Task command SDK definition - ([`4944078`](https://github.com/canvas-medical/canvas-plugins/commit/49440781416d56c8769b2e83ce78bd616e6b6f1a)) +- Add LabOrder command SDK definition + ([`3348685`](https://github.com/canvas-medical/canvas-plugins/commit/3348685fb28ad9ea010e26c56550e10d545cf53f)) - Add MedicationHistory command SDK definition ([`e64238d`](https://github.com/canvas-medical/canvas-plugins/commit/e64238d7e1b8f54ccf43ff78248620497cb329b7)) @@ -574,23 +604,20 @@ Signed-off-by: dependabot[bot] Co-authored-by: dependabot[b - Add PastSurgicalHistory command SDK definition ([`332f898`](https://github.com/canvas-medical/canvas-plugins/commit/332f898fccb7422a495cf1914e5a301ed763a946)) -- Feat: add RemoveAllergy command SDK definition - ([`40fa8d3`](https://github.com/canvas-medical/canvas-plugins/commit/40fa8d3afdb5e2beecac545dfe513dfec24cb6a0)) - -- Add Allergy command SDK definition - ([`87f05cf`](https://github.com/canvas-medical/canvas-plugins/commit/87f05cf16813e267b9cba7c8c947cee171dd44fd)) +- Add Refill command SDK definition + ([`36b3e1e`](https://github.com/canvas-medical/canvas-plugins/commit/36b3e1e6c259562fa66e9e3ddfdc1c138a087e75)) -- Add FamilyHistory command SDK definition - ([`a77fa6d`](https://github.com/canvas-medical/canvas-plugins/commit/a77fa6dcb6f742827955da8c9afa7c1a83636480)) +- Add Task command SDK definition + ([`4944078`](https://github.com/canvas-medical/canvas-plugins/commit/49440781416d56c8769b2e83ce78bd616e6b6f1a)) -- Add LabOrder command SDK definition - ([`3348685`](https://github.com/canvas-medical/canvas-plugins/commit/3348685fb28ad9ea010e26c56550e10d545cf53f)) +- Add UpdateDiagnosis command SDK definition + ([`f751d07`](https://github.com/canvas-medical/canvas-plugins/commit/f751d074a4758a704c3de2ee4ba69470daf18f0b)) -- Add instruct and perform commands - ([`08997ed`](https://github.com/canvas-medical/canvas-plugins/commit/08997ed5f96bb2971eeed9a179704ffacaab6494)) +- Add Vitals command SDK definition + ([`ad56f11`](https://github.com/canvas-medical/canvas-plugins/commit/ad56f1193d58e73b9cf5aef81e9c5787b8879a8e)) -- Add effects for Perform Command - ([`b379a28`](https://github.com/canvas-medical/canvas-plugins/commit/b379a289ac483ed1dcc1463b20bb7671aa43ba11)) +- Feat: add RemoveAllergy command SDK definition + ([`40fa8d3`](https://github.com/canvas-medical/canvas-plugins/commit/40fa8d3afdb5e2beecac545dfe513dfec24cb6a0)) ## v0.2.5 (2024-09-09) diff --git a/plugin_runner/plugin_installer.py b/plugin_runner/plugin_installer.py new file mode 100644 index 00000000..2af96ebc --- /dev/null +++ b/plugin_runner/plugin_installer.py @@ -0,0 +1,205 @@ +import json +import os +import shutil +import tarfile +import tempfile +import zipfile +from pathlib import Path +from typing import Any +from urllib import parse + +import boto3 +import psycopg +from psycopg import Connection + +import settings + +Archive = zipfile.ZipFile | tarfile.TarFile +# Plugin "packages" include this prefix in the database record for the plugin and the S3 bucket key. +UPLOAD_TO_PREFIX = "plugins" + + +class PluginError(Exception): + """An exception raised for plugin-related errors.""" + + +class PluginValidationError(PluginError): + """An exception raised when a plugin package is not valid.""" + + +class InvalidPluginFormat(PluginValidationError): + """An exception raised when the plugin file format is not supported.""" + + +class PluginInstallationError(PluginError): + """An exception raised when a plugin fails to install.""" + + +def get_database_dict_from_url() -> dict[str, Any]: + """Creates a psycopg ready dictionary from the home-app database URL.""" + parsed_url = parse.urlparse(os.getenv("DATABASE_URL")) + db_name = parsed_url.path[1:] + return { + "dbname": db_name, + "user": parsed_url.username, + "password": parsed_url.password, + "host": parsed_url.hostname, + "port": parsed_url.port, + } + + +def get_database_dict_from_env() -> dict[str, Any]: + """Creates a psycopg ready dictionary from the environment variables.""" + return { + "dbname": "home-app", + "user": os.getenv("DB_USERNAME", "app"), + "password": os.getenv("DB_PASSWORD", "app"), + "host": os.getenv("DB_HOST", "home-app-db"), + "port": os.getenv("DB_PORT", "5432"), + } + + +def open_database_connection() -> Connection: + """Opens a psycopg connection to the home-app database.""" + # When running within Aptible, use the database URL, otherwise pull from the environment variables. + if os.getenv("DATABASE_URL"): + database_dict = get_database_dict_from_url() + else: + database_dict = get_database_dict_from_env() + conn = psycopg.connect(**database_dict) + return conn + + +def enabled_plugins() -> dict[str, dict[str, str | dict[str, str]]]: + """Returns a dictionary of enabled plugins and their attributes.""" + conn = open_database_connection() + + plugins = {} + + with conn.cursor() as cursor: + cursor.execute( + "select name, package, version, key, value from plugin_io_plugin p " + "join plugin_io_pluginsecret s on p.id = s.plugin_id where is_enabled" + ) + rows = cursor.fetchall() + for row in rows: + if row["name"] not in plugins: + plugins[row["name"]] = { + "version": row["version"], + "package": row["package"], + "secrets": {row["key"]: row["value"]}, + } + else: + plugins[row["name"]]["secrets"][row["key"]] = row["value"] + + return plugins + + +def download_plugin(plugin_package: str) -> Path: + """Download the plugin package from the S3 bucket.""" + s3 = boto3.client("s3") + temp_dir = tempfile.TemporaryDirectory() + prefix_dir = os.path.join(temp_dir.name, UPLOAD_TO_PREFIX) + os.mkdir(prefix_dir) # create an intermediate directory reflecting the prefix + with open(os.path.join(temp_dir.name, plugin_package), "wb") as download_file: + s3.download_fileobj( + "canvas-client-media", f"{settings.CUSTOMER_IDENTIFIER}/{plugin_package}", download_file + ) + return Path(os.path.join(temp_dir.name, plugin_package)) + + +def install_plugin(plugin_name: str, attributes: dict[str, str | dict[str, str]]) -> None: + """Install the given Plugin's package into the runtime.""" + try: + print(f"Installing plugin '{plugin_name}'") + + plugin_installation_path = Path(os.path.join(settings.PLUGIN_DIRECTORY, plugin_name)) + + # if plugin exists, first uninstall it + if plugin_installation_path.exists(): + uninstall_plugin(plugin_name) + + plugin_file_path = download_plugin(attributes["package"]) + extract_plugin(plugin_file_path, plugin_installation_path) + + install_plugin_secrets(plugin_name=plugin_name, secrets=attributes["secrets"]) + except Exception as ex: + print(f"Failed to install plugin '{plugin_name}', version {attributes['version']}") + raise PluginInstallationError() from ex + + +def extract_plugin(plugin_file_path: Path, plugin_installation_path: Path) -> None: + """Extract plugin in `file` to the given `path`.""" + archive: Archive | None = None + + try: + if zipfile.is_zipfile(plugin_file_path): + archive = zipfile.ZipFile(plugin_file_path) + archive.extractall(plugin_installation_path) + elif tarfile.is_tarfile(plugin_file_path): + try: + with open(plugin_file_path, "rb") as file: + archive = tarfile.TarFile.open(fileobj=file) + archive.extractall(plugin_installation_path, filter="data") + except tarfile.ReadError as ex: + print(f"Unreadable tar archive: '{plugin_file_path}'") + raise InvalidPluginFormat from ex + else: + print(f"Unsupported file format: '{plugin_file_path}'") + raise InvalidPluginFormat + finally: + if archive: + archive.close() + + +def install_plugin_secrets(plugin_name: str, secrets: dict[str, str]) -> None: + """Write the plugin's secrets to disk in the package's directory.""" + print(f"Writing plugin secrets for '{plugin_name}'") + + secrets_path = os.path.join(settings.PLUGIN_DIRECTORY, plugin_name, settings.SECRETS_FILE_NAME) + + # Did the plugin ship a secrets.json? TOO BAD, IT'S GONE NOW. + if Path(secrets_path).exists(): + os.remove(secrets_path) + + with open(str(secrets_path), "w") as f: + json.dump(secrets, f) + + +def disable_plugin(plugin_name: str) -> None: + """Disable the given plugin.""" + conn = open_database_connection() + conn.cursor().execute( + "update plugin_io_plugin set is_enabled = false where name = %s", (plugin_name,) + ) + + uninstall_plugin(plugin_name) + + +def uninstall_plugin(plugin_name: str) -> None: + """Remove the plugin from the filesystem.""" + plugin_path = Path(os.path.join(settings.PLUGIN_DIRECTORY, plugin_name)) + + if plugin_path.exists(): + shutil.rmtree(plugin_path) + + +def install_plugins() -> None: + """Install all enabled plugins.""" + if Path(settings.PLUGIN_DIRECTORY).exists(): + shutil.rmtree(settings.PLUGIN_DIRECTORY) + + os.mkdir(settings.PLUGIN_DIRECTORY) + + for plugin_name, attributes in enabled_plugins().items(): + try: + print(f"Installing plugin '{plugin_name}', version {attributes['version']}") + install_plugin(plugin_name, attributes) + except PluginInstallationError: + disable_plugin(plugin_name) + print( + f"Installation failed for plugin '{plugin_name}', version {attributes['version']}. The plugin has been disabled" + ) + continue + + return None diff --git a/plugin_runner/plugin_synchronizer.py b/plugin_runner/plugin_synchronizer.py index 83b3273e..3ba614f8 100755 --- a/plugin_runner/plugin_synchronizer.py +++ b/plugin_runner/plugin_synchronizer.py @@ -7,6 +7,8 @@ import redis +from plugin_runner.plugin_installer import install_plugins + APP_NAME = os.getenv("APP_NAME") CUSTOMER_IDENTIFIER = os.getenv("CUSTOMER_IDENTIFIER") @@ -62,17 +64,13 @@ def main() -> None: if "action" not in data or "client_id" not in data: return - # Don't respond to our own messages - if data["client_id"] == CLIENT_ID: - return - if data["action"] == "restart": # Run the plugin installer process try: print("plugin-synchronizer: installing plugins") - check_output(["./manage.py", "install_plugins_v2"], cwd="/app", stderr=STDOUT) + install_plugins() except CalledProcessError as e: - print("plugin-synchronizer: `./manage.py install_plugins_v2` failed:", e) + print("plugin-synchronizer: `install_plugins` failed:", e) try: print("plugin-synchronizer: sending SIGHUP to plugin-runner") diff --git a/plugin_runner/tests/test_plugin_installer.py b/plugin_runner/tests/test_plugin_installer.py new file mode 100644 index 00000000..be32a273 --- /dev/null +++ b/plugin_runner/tests/test_plugin_installer.py @@ -0,0 +1,117 @@ +import json +import tarfile +import tempfile +import zipfile +from pathlib import Path + +from pytest_mock import MockerFixture + +from plugin_runner.plugin_installer import install_plugins, uninstall_plugin + + +def _create_tarball(name: str) -> Path: + # Create a temporary tarball file + temp_dir = tempfile.tempdir + tarball_path = Path(f"{temp_dir}/{name}.tar.gz") + + # Add some files to the tarball + with tarfile.open(tarball_path, "w:gz") as tar: + for i in range(3): + file_path = Path(temp_dir) / f"file{i}.txt" + file_path.write_text(f"Content of file {i}") + tar.add(file_path, arcname=f"file{i}.txt") + + # Return a Path handle to the tarball + return tarball_path + + +def _create_zip_archive(name: str) -> Path: + # Create a temporary zip file + temp_dir = tempfile.tempdir + zip_path = Path(f"{temp_dir}/{name}.zip") + + # Add some files to the zip archive + with zipfile.ZipFile(zip_path, "w") as zipf: + for i in range(3): + file_path = Path(temp_dir) / f"file{i}.txt" + file_path.write_text(f"Content of file {i}") + zipf.write(file_path, arcname=f"file{i}.txt") + + # Return a Path handle to the zip archive + return zip_path + + +def test_plugin_installation_from_tarball(mocker: MockerFixture) -> None: + """Test that plugins can be installed from tarballs.""" + mock_plugins = { + "plugin1": { + "version": "1.0", + "package": "plugins/plugin1.tar.gz", + "secrets": {"key1": "value1"}, + }, + "plugin2": { + "version": "2.0", + "package": "plugins/plugin2.tar.gz", + "secrets": {"key2": "value2"}, + }, + } + + tarball_1 = _create_tarball("plugin1") + tarball_2 = _create_tarball("plugin2") + + mocker.patch("plugin_runner.plugin_installer.enabled_plugins", return_value=mock_plugins) + mocker.patch( + "plugin_runner.plugin_installer.download_plugin", side_effect=[tarball_1, tarball_2] + ) + + install_plugins() + assert Path("plugin_runner/tests/data/plugins/plugin1").exists() + assert Path("plugin_runner/tests/data/plugins/plugin1/SECRETS.json").exists() + with open("plugin_runner/tests/data/plugins/plugin1/SECRETS.json") as f: + assert json.load(f) == mock_plugins["plugin1"]["secrets"] + assert Path("plugin_runner/tests/data/plugins/plugin2").exists() + assert Path("plugin_runner/tests/data/plugins/plugin2/SECRETS.json").exists() + with open("plugin_runner/tests/data/plugins/plugin2/SECRETS.json") as f: + assert json.load(f) == mock_plugins["plugin2"]["secrets"] + + uninstall_plugin("plugin1") + uninstall_plugin("plugin2") + assert not Path("plugin_runner/tests/data/plugins/plugin1").exists() + assert not Path("plugin_runner/tests/data/plugins/plugin2").exists() + + +def test_plugin_installation_from_zip_archive(mocker: MockerFixture) -> None: + """Test that plugins can be installed from zip archives.""" + mock_plugins = { + "plugin1": { + "version": "1.0", + "package": "plugins/plugin1.zip", + "secrets": {"key1": "value1"}, + }, + "plugin2": { + "version": "2.0", + "package": "plugins/plugin2.zip", + "secrets": {"key2": "value2"}, + }, + } + + zip_1 = _create_zip_archive("plugin1") + zip_2 = _create_zip_archive("plugin2") + + mocker.patch("plugin_runner.plugin_installer.enabled_plugins", return_value=mock_plugins) + mocker.patch("plugin_runner.plugin_installer.download_plugin", side_effect=[zip_1, zip_2]) + + install_plugins() + assert Path("plugin_runner/tests/data/plugins/plugin1").exists() + assert Path("plugin_runner/tests/data/plugins/plugin1/SECRETS.json").exists() + with open("plugin_runner/tests/data/plugins/plugin1/SECRETS.json") as f: + assert json.load(f) == mock_plugins["plugin1"]["secrets"] + assert Path("plugin_runner/tests/data/plugins/plugin2").exists() + assert Path("plugin_runner/tests/data/plugins/plugin2/SECRETS.json").exists() + with open("plugin_runner/tests/data/plugins/plugin2/SECRETS.json") as f: + assert json.load(f) == mock_plugins["plugin2"]["secrets"] + + uninstall_plugin("plugin1") + uninstall_plugin("plugin2") + assert not Path("plugin_runner/tests/data/plugins/plugin1").exists() + assert not Path("plugin_runner/tests/data/plugins/plugin2").exists() diff --git a/poetry.lock b/poetry.lock index cc83ece0..55a04cbb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -121,6 +121,489 @@ files = [ [package.dependencies] chardet = ">=3.0.2" +[[package]] +name = "boto3" +version = "1.35.91" +description = "The AWS SDK for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "boto3-1.35.91-py3-none-any.whl", hash = "sha256:eecef248f8743ab30036cd9c916808a0892fc9036e1a35434d8222060c08bbd2"}, + {file = "boto3-1.35.91.tar.gz", hash = "sha256:ba391982f6cada136c5bba99e85d7fe1bc4e157c53a22a78e4aca35d1b39152e"}, +] + +[package.dependencies] +botocore = ">=1.35.91,<1.36.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.10.0,<0.11.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] + +[[package]] +name = "boto3-stubs" +version = "1.35.91" +description = "Type annotations for boto3 1.35.91 generated with mypy-boto3-builder 8.7.1" +optional = false +python-versions = ">=3.8" +files = [ + {file = "boto3_stubs-1.35.91-py3-none-any.whl", hash = "sha256:e4301b9d05b31fbfea382d0d1d950c2178f7fca03058b31373fac9a4cdf89438"}, + {file = "boto3_stubs-1.35.91.tar.gz", hash = "sha256:780f71406147b78f9860d78907b5c015874537d821364588ec837c4cd1eecf91"}, +] + +[package.dependencies] +botocore-stubs = "*" +mypy-boto3-s3 = {version = ">=1.35.0,<1.36.0", optional = true, markers = "extra == \"s3\""} +types-s3transfer = "*" +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + +[package.extras] +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-backupsearch (>=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-bcm-pricing-calculator (>=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-data-automation (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-data-automation-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)", "mypy-boto3-billing (>=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-connectcampaignsv2 (>=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-dsql (>=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-geo-maps (>=1.35.0,<1.36.0)", "mypy-boto3-geo-places (>=1.35.0,<1.36.0)", "mypy-boto3-geo-routes (>=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-invoicing (>=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-marketplace-reporting (>=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-networkflowmonitor (>=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-notifications (>=1.35.0,<1.36.0)", "mypy-boto3-notificationscontacts (>=1.35.0,<1.36.0)", "mypy-boto3-oam (>=1.35.0,<1.36.0)", "mypy-boto3-observabilityadmin (>=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-partnercentral-selling (>=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-s3tables (>=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-security-ir (>=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-socialmessaging (>=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-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)"] +amplifyuibuilder = ["mypy-boto3-amplifyuibuilder (>=1.35.0,<1.36.0)"] +apigateway = ["mypy-boto3-apigateway (>=1.35.0,<1.36.0)"] +apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (>=1.35.0,<1.36.0)"] +apigatewayv2 = ["mypy-boto3-apigatewayv2 (>=1.35.0,<1.36.0)"] +appconfig = ["mypy-boto3-appconfig (>=1.35.0,<1.36.0)"] +appconfigdata = ["mypy-boto3-appconfigdata (>=1.35.0,<1.36.0)"] +appfabric = ["mypy-boto3-appfabric (>=1.35.0,<1.36.0)"] +appflow = ["mypy-boto3-appflow (>=1.35.0,<1.36.0)"] +appintegrations = ["mypy-boto3-appintegrations (>=1.35.0,<1.36.0)"] +application-autoscaling = ["mypy-boto3-application-autoscaling (>=1.35.0,<1.36.0)"] +application-insights = ["mypy-boto3-application-insights (>=1.35.0,<1.36.0)"] +application-signals = ["mypy-boto3-application-signals (>=1.35.0,<1.36.0)"] +applicationcostprofiler = ["mypy-boto3-applicationcostprofiler (>=1.35.0,<1.36.0)"] +appmesh = ["mypy-boto3-appmesh (>=1.35.0,<1.36.0)"] +apprunner = ["mypy-boto3-apprunner (>=1.35.0,<1.36.0)"] +appstream = ["mypy-boto3-appstream (>=1.35.0,<1.36.0)"] +appsync = ["mypy-boto3-appsync (>=1.35.0,<1.36.0)"] +apptest = ["mypy-boto3-apptest (>=1.35.0,<1.36.0)"] +arc-zonal-shift = ["mypy-boto3-arc-zonal-shift (>=1.35.0,<1.36.0)"] +artifact = ["mypy-boto3-artifact (>=1.35.0,<1.36.0)"] +athena = ["mypy-boto3-athena (>=1.35.0,<1.36.0)"] +auditmanager = ["mypy-boto3-auditmanager (>=1.35.0,<1.36.0)"] +autoscaling = ["mypy-boto3-autoscaling (>=1.35.0,<1.36.0)"] +autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.35.0,<1.36.0)"] +b2bi = ["mypy-boto3-b2bi (>=1.35.0,<1.36.0)"] +backup = ["mypy-boto3-backup (>=1.35.0,<1.36.0)"] +backup-gateway = ["mypy-boto3-backup-gateway (>=1.35.0,<1.36.0)"] +backupsearch = ["mypy-boto3-backupsearch (>=1.35.0,<1.36.0)"] +batch = ["mypy-boto3-batch (>=1.35.0,<1.36.0)"] +bcm-data-exports = ["mypy-boto3-bcm-data-exports (>=1.35.0,<1.36.0)"] +bcm-pricing-calculator = ["mypy-boto3-bcm-pricing-calculator (>=1.35.0,<1.36.0)"] +bedrock = ["mypy-boto3-bedrock (>=1.35.0,<1.36.0)"] +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-data-automation = ["mypy-boto3-bedrock-data-automation (>=1.35.0,<1.36.0)"] +bedrock-data-automation-runtime = ["mypy-boto3-bedrock-data-automation-runtime (>=1.35.0,<1.36.0)"] +bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.35.0,<1.36.0)"] +billing = ["mypy-boto3-billing (>=1.35.0,<1.36.0)"] +billingconductor = ["mypy-boto3-billingconductor (>=1.35.0,<1.36.0)"] +boto3 = ["boto3 (==1.35.91)"] +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)"] +chatbot = ["mypy-boto3-chatbot (>=1.35.0,<1.36.0)"] +chime = ["mypy-boto3-chime (>=1.35.0,<1.36.0)"] +chime-sdk-identity = ["mypy-boto3-chime-sdk-identity (>=1.35.0,<1.36.0)"] +chime-sdk-media-pipelines = ["mypy-boto3-chime-sdk-media-pipelines (>=1.35.0,<1.36.0)"] +chime-sdk-meetings = ["mypy-boto3-chime-sdk-meetings (>=1.35.0,<1.36.0)"] +chime-sdk-messaging = ["mypy-boto3-chime-sdk-messaging (>=1.35.0,<1.36.0)"] +chime-sdk-voice = ["mypy-boto3-chime-sdk-voice (>=1.35.0,<1.36.0)"] +cleanrooms = ["mypy-boto3-cleanrooms (>=1.35.0,<1.36.0)"] +cleanroomsml = ["mypy-boto3-cleanroomsml (>=1.35.0,<1.36.0)"] +cloud9 = ["mypy-boto3-cloud9 (>=1.35.0,<1.36.0)"] +cloudcontrol = ["mypy-boto3-cloudcontrol (>=1.35.0,<1.36.0)"] +clouddirectory = ["mypy-boto3-clouddirectory (>=1.35.0,<1.36.0)"] +cloudformation = ["mypy-boto3-cloudformation (>=1.35.0,<1.36.0)"] +cloudfront = ["mypy-boto3-cloudfront (>=1.35.0,<1.36.0)"] +cloudfront-keyvaluestore = ["mypy-boto3-cloudfront-keyvaluestore (>=1.35.0,<1.36.0)"] +cloudhsm = ["mypy-boto3-cloudhsm (>=1.35.0,<1.36.0)"] +cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (>=1.35.0,<1.36.0)"] +cloudsearch = ["mypy-boto3-cloudsearch (>=1.35.0,<1.36.0)"] +cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.35.0,<1.36.0)"] +cloudtrail = ["mypy-boto3-cloudtrail (>=1.35.0,<1.36.0)"] +cloudtrail-data = ["mypy-boto3-cloudtrail-data (>=1.35.0,<1.36.0)"] +cloudwatch = ["mypy-boto3-cloudwatch (>=1.35.0,<1.36.0)"] +codeartifact = ["mypy-boto3-codeartifact (>=1.35.0,<1.36.0)"] +codebuild = ["mypy-boto3-codebuild (>=1.35.0,<1.36.0)"] +codecatalyst = ["mypy-boto3-codecatalyst (>=1.35.0,<1.36.0)"] +codecommit = ["mypy-boto3-codecommit (>=1.35.0,<1.36.0)"] +codeconnections = ["mypy-boto3-codeconnections (>=1.35.0,<1.36.0)"] +codedeploy = ["mypy-boto3-codedeploy (>=1.35.0,<1.36.0)"] +codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (>=1.35.0,<1.36.0)"] +codeguru-security = ["mypy-boto3-codeguru-security (>=1.35.0,<1.36.0)"] +codeguruprofiler = ["mypy-boto3-codeguruprofiler (>=1.35.0,<1.36.0)"] +codepipeline = ["mypy-boto3-codepipeline (>=1.35.0,<1.36.0)"] +codestar-connections = ["mypy-boto3-codestar-connections (>=1.35.0,<1.36.0)"] +codestar-notifications = ["mypy-boto3-codestar-notifications (>=1.35.0,<1.36.0)"] +cognito-identity = ["mypy-boto3-cognito-identity (>=1.35.0,<1.36.0)"] +cognito-idp = ["mypy-boto3-cognito-idp (>=1.35.0,<1.36.0)"] +cognito-sync = ["mypy-boto3-cognito-sync (>=1.35.0,<1.36.0)"] +comprehend = ["mypy-boto3-comprehend (>=1.35.0,<1.36.0)"] +comprehendmedical = ["mypy-boto3-comprehendmedical (>=1.35.0,<1.36.0)"] +compute-optimizer = ["mypy-boto3-compute-optimizer (>=1.35.0,<1.36.0)"] +config = ["mypy-boto3-config (>=1.35.0,<1.36.0)"] +connect = ["mypy-boto3-connect (>=1.35.0,<1.36.0)"] +connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.35.0,<1.36.0)"] +connectcampaigns = ["mypy-boto3-connectcampaigns (>=1.35.0,<1.36.0)"] +connectcampaignsv2 = ["mypy-boto3-connectcampaignsv2 (>=1.35.0,<1.36.0)"] +connectcases = ["mypy-boto3-connectcases (>=1.35.0,<1.36.0)"] +connectparticipant = ["mypy-boto3-connectparticipant (>=1.35.0,<1.36.0)"] +controlcatalog = ["mypy-boto3-controlcatalog (>=1.35.0,<1.36.0)"] +controltower = ["mypy-boto3-controltower (>=1.35.0,<1.36.0)"] +cost-optimization-hub = ["mypy-boto3-cost-optimization-hub (>=1.35.0,<1.36.0)"] +cur = ["mypy-boto3-cur (>=1.35.0,<1.36.0)"] +customer-profiles = ["mypy-boto3-customer-profiles (>=1.35.0,<1.36.0)"] +databrew = ["mypy-boto3-databrew (>=1.35.0,<1.36.0)"] +dataexchange = ["mypy-boto3-dataexchange (>=1.35.0,<1.36.0)"] +datapipeline = ["mypy-boto3-datapipeline (>=1.35.0,<1.36.0)"] +datasync = ["mypy-boto3-datasync (>=1.35.0,<1.36.0)"] +datazone = ["mypy-boto3-datazone (>=1.35.0,<1.36.0)"] +dax = ["mypy-boto3-dax (>=1.35.0,<1.36.0)"] +deadline = ["mypy-boto3-deadline (>=1.35.0,<1.36.0)"] +detective = ["mypy-boto3-detective (>=1.35.0,<1.36.0)"] +devicefarm = ["mypy-boto3-devicefarm (>=1.35.0,<1.36.0)"] +devops-guru = ["mypy-boto3-devops-guru (>=1.35.0,<1.36.0)"] +directconnect = ["mypy-boto3-directconnect (>=1.35.0,<1.36.0)"] +discovery = ["mypy-boto3-discovery (>=1.35.0,<1.36.0)"] +dlm = ["mypy-boto3-dlm (>=1.35.0,<1.36.0)"] +dms = ["mypy-boto3-dms (>=1.35.0,<1.36.0)"] +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)"] +dsql = ["mypy-boto3-dsql (>=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)"] +ec2 = ["mypy-boto3-ec2 (>=1.35.0,<1.36.0)"] +ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (>=1.35.0,<1.36.0)"] +ecr = ["mypy-boto3-ecr (>=1.35.0,<1.36.0)"] +ecr-public = ["mypy-boto3-ecr-public (>=1.35.0,<1.36.0)"] +ecs = ["mypy-boto3-ecs (>=1.35.0,<1.36.0)"] +efs = ["mypy-boto3-efs (>=1.35.0,<1.36.0)"] +eks = ["mypy-boto3-eks (>=1.35.0,<1.36.0)"] +eks-auth = ["mypy-boto3-eks-auth (>=1.35.0,<1.36.0)"] +elastic-inference = ["mypy-boto3-elastic-inference (>=1.35.0,<1.36.0)"] +elasticache = ["mypy-boto3-elasticache (>=1.35.0,<1.36.0)"] +elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (>=1.35.0,<1.36.0)"] +elastictranscoder = ["mypy-boto3-elastictranscoder (>=1.35.0,<1.36.0)"] +elb = ["mypy-boto3-elb (>=1.35.0,<1.36.0)"] +elbv2 = ["mypy-boto3-elbv2 (>=1.35.0,<1.36.0)"] +emr = ["mypy-boto3-emr (>=1.35.0,<1.36.0)"] +emr-containers = ["mypy-boto3-emr-containers (>=1.35.0,<1.36.0)"] +emr-serverless = ["mypy-boto3-emr-serverless (>=1.35.0,<1.36.0)"] +entityresolution = ["mypy-boto3-entityresolution (>=1.35.0,<1.36.0)"] +es = ["mypy-boto3-es (>=1.35.0,<1.36.0)"] +essential = ["mypy-boto3-cloudformation (>=1.35.0,<1.36.0)", "mypy-boto3-dynamodb (>=1.35.0,<1.36.0)", "mypy-boto3-ec2 (>=1.35.0,<1.36.0)", "mypy-boto3-lambda (>=1.35.0,<1.36.0)", "mypy-boto3-rds (>=1.35.0,<1.36.0)", "mypy-boto3-s3 (>=1.35.0,<1.36.0)", "mypy-boto3-sqs (>=1.35.0,<1.36.0)"] +events = ["mypy-boto3-events (>=1.35.0,<1.36.0)"] +evidently = ["mypy-boto3-evidently (>=1.35.0,<1.36.0)"] +finspace = ["mypy-boto3-finspace (>=1.35.0,<1.36.0)"] +finspace-data = ["mypy-boto3-finspace-data (>=1.35.0,<1.36.0)"] +firehose = ["mypy-boto3-firehose (>=1.35.0,<1.36.0)"] +fis = ["mypy-boto3-fis (>=1.35.0,<1.36.0)"] +fms = ["mypy-boto3-fms (>=1.35.0,<1.36.0)"] +forecast = ["mypy-boto3-forecast (>=1.35.0,<1.36.0)"] +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 (>=1.35.0,<1.36.0)"] +gamelift = ["mypy-boto3-gamelift (>=1.35.0,<1.36.0)"] +geo-maps = ["mypy-boto3-geo-maps (>=1.35.0,<1.36.0)"] +geo-places = ["mypy-boto3-geo-places (>=1.35.0,<1.36.0)"] +geo-routes = ["mypy-boto3-geo-routes (>=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)"] +glue = ["mypy-boto3-glue (>=1.35.0,<1.36.0)"] +grafana = ["mypy-boto3-grafana (>=1.35.0,<1.36.0)"] +greengrass = ["mypy-boto3-greengrass (>=1.35.0,<1.36.0)"] +greengrassv2 = ["mypy-boto3-greengrassv2 (>=1.35.0,<1.36.0)"] +groundstation = ["mypy-boto3-groundstation (>=1.35.0,<1.36.0)"] +guardduty = ["mypy-boto3-guardduty (>=1.35.0,<1.36.0)"] +health = ["mypy-boto3-health (>=1.35.0,<1.36.0)"] +healthlake = ["mypy-boto3-healthlake (>=1.35.0,<1.36.0)"] +iam = ["mypy-boto3-iam (>=1.35.0,<1.36.0)"] +identitystore = ["mypy-boto3-identitystore (>=1.35.0,<1.36.0)"] +imagebuilder = ["mypy-boto3-imagebuilder (>=1.35.0,<1.36.0)"] +importexport = ["mypy-boto3-importexport (>=1.35.0,<1.36.0)"] +inspector = ["mypy-boto3-inspector (>=1.35.0,<1.36.0)"] +inspector-scan = ["mypy-boto3-inspector-scan (>=1.35.0,<1.36.0)"] +inspector2 = ["mypy-boto3-inspector2 (>=1.35.0,<1.36.0)"] +internetmonitor = ["mypy-boto3-internetmonitor (>=1.35.0,<1.36.0)"] +invoicing = ["mypy-boto3-invoicing (>=1.35.0,<1.36.0)"] +iot = ["mypy-boto3-iot (>=1.35.0,<1.36.0)"] +iot-data = ["mypy-boto3-iot-data (>=1.35.0,<1.36.0)"] +iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.35.0,<1.36.0)"] +iot1click-devices = ["mypy-boto3-iot1click-devices (>=1.35.0,<1.36.0)"] +iot1click-projects = ["mypy-boto3-iot1click-projects (>=1.35.0,<1.36.0)"] +iotanalytics = ["mypy-boto3-iotanalytics (>=1.35.0,<1.36.0)"] +iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.35.0,<1.36.0)"] +iotevents = ["mypy-boto3-iotevents (>=1.35.0,<1.36.0)"] +iotevents-data = ["mypy-boto3-iotevents-data (>=1.35.0,<1.36.0)"] +iotfleethub = ["mypy-boto3-iotfleethub (>=1.35.0,<1.36.0)"] +iotfleetwise = ["mypy-boto3-iotfleetwise (>=1.35.0,<1.36.0)"] +iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.35.0,<1.36.0)"] +iotsitewise = ["mypy-boto3-iotsitewise (>=1.35.0,<1.36.0)"] +iotthingsgraph = ["mypy-boto3-iotthingsgraph (>=1.35.0,<1.36.0)"] +iottwinmaker = ["mypy-boto3-iottwinmaker (>=1.35.0,<1.36.0)"] +iotwireless = ["mypy-boto3-iotwireless (>=1.35.0,<1.36.0)"] +ivs = ["mypy-boto3-ivs (>=1.35.0,<1.36.0)"] +ivs-realtime = ["mypy-boto3-ivs-realtime (>=1.35.0,<1.36.0)"] +ivschat = ["mypy-boto3-ivschat (>=1.35.0,<1.36.0)"] +kafka = ["mypy-boto3-kafka (>=1.35.0,<1.36.0)"] +kafkaconnect = ["mypy-boto3-kafkaconnect (>=1.35.0,<1.36.0)"] +kendra = ["mypy-boto3-kendra (>=1.35.0,<1.36.0)"] +kendra-ranking = ["mypy-boto3-kendra-ranking (>=1.35.0,<1.36.0)"] +keyspaces = ["mypy-boto3-keyspaces (>=1.35.0,<1.36.0)"] +kinesis = ["mypy-boto3-kinesis (>=1.35.0,<1.36.0)"] +kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (>=1.35.0,<1.36.0)"] +kinesis-video-media = ["mypy-boto3-kinesis-video-media (>=1.35.0,<1.36.0)"] +kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (>=1.35.0,<1.36.0)"] +kinesis-video-webrtc-storage = ["mypy-boto3-kinesis-video-webrtc-storage (>=1.35.0,<1.36.0)"] +kinesisanalytics = ["mypy-boto3-kinesisanalytics (>=1.35.0,<1.36.0)"] +kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (>=1.35.0,<1.36.0)"] +kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.35.0,<1.36.0)"] +kms = ["mypy-boto3-kms (>=1.35.0,<1.36.0)"] +lakeformation = ["mypy-boto3-lakeformation (>=1.35.0,<1.36.0)"] +lambda = ["mypy-boto3-lambda (>=1.35.0,<1.36.0)"] +launch-wizard = ["mypy-boto3-launch-wizard (>=1.35.0,<1.36.0)"] +lex-models = ["mypy-boto3-lex-models (>=1.35.0,<1.36.0)"] +lex-runtime = ["mypy-boto3-lex-runtime (>=1.35.0,<1.36.0)"] +lexv2-models = ["mypy-boto3-lexv2-models (>=1.35.0,<1.36.0)"] +lexv2-runtime = ["mypy-boto3-lexv2-runtime (>=1.35.0,<1.36.0)"] +license-manager = ["mypy-boto3-license-manager (>=1.35.0,<1.36.0)"] +license-manager-linux-subscriptions = ["mypy-boto3-license-manager-linux-subscriptions (>=1.35.0,<1.36.0)"] +license-manager-user-subscriptions = ["mypy-boto3-license-manager-user-subscriptions (>=1.35.0,<1.36.0)"] +lightsail = ["mypy-boto3-lightsail (>=1.35.0,<1.36.0)"] +location = ["mypy-boto3-location (>=1.35.0,<1.36.0)"] +logs = ["mypy-boto3-logs (>=1.35.0,<1.36.0)"] +lookoutequipment = ["mypy-boto3-lookoutequipment (>=1.35.0,<1.36.0)"] +lookoutmetrics = ["mypy-boto3-lookoutmetrics (>=1.35.0,<1.36.0)"] +lookoutvision = ["mypy-boto3-lookoutvision (>=1.35.0,<1.36.0)"] +m2 = ["mypy-boto3-m2 (>=1.35.0,<1.36.0)"] +machinelearning = ["mypy-boto3-machinelearning (>=1.35.0,<1.36.0)"] +macie2 = ["mypy-boto3-macie2 (>=1.35.0,<1.36.0)"] +mailmanager = ["mypy-boto3-mailmanager (>=1.35.0,<1.36.0)"] +managedblockchain = ["mypy-boto3-managedblockchain (>=1.35.0,<1.36.0)"] +managedblockchain-query = ["mypy-boto3-managedblockchain-query (>=1.35.0,<1.36.0)"] +marketplace-agreement = ["mypy-boto3-marketplace-agreement (>=1.35.0,<1.36.0)"] +marketplace-catalog = ["mypy-boto3-marketplace-catalog (>=1.35.0,<1.36.0)"] +marketplace-deployment = ["mypy-boto3-marketplace-deployment (>=1.35.0,<1.36.0)"] +marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (>=1.35.0,<1.36.0)"] +marketplace-reporting = ["mypy-boto3-marketplace-reporting (>=1.35.0,<1.36.0)"] +marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (>=1.35.0,<1.36.0)"] +mediaconnect = ["mypy-boto3-mediaconnect (>=1.35.0,<1.36.0)"] +mediaconvert = ["mypy-boto3-mediaconvert (>=1.35.0,<1.36.0)"] +medialive = ["mypy-boto3-medialive (>=1.35.0,<1.36.0)"] +mediapackage = ["mypy-boto3-mediapackage (>=1.35.0,<1.36.0)"] +mediapackage-vod = ["mypy-boto3-mediapackage-vod (>=1.35.0,<1.36.0)"] +mediapackagev2 = ["mypy-boto3-mediapackagev2 (>=1.35.0,<1.36.0)"] +mediastore = ["mypy-boto3-mediastore (>=1.35.0,<1.36.0)"] +mediastore-data = ["mypy-boto3-mediastore-data (>=1.35.0,<1.36.0)"] +mediatailor = ["mypy-boto3-mediatailor (>=1.35.0,<1.36.0)"] +medical-imaging = ["mypy-boto3-medical-imaging (>=1.35.0,<1.36.0)"] +memorydb = ["mypy-boto3-memorydb (>=1.35.0,<1.36.0)"] +meteringmarketplace = ["mypy-boto3-meteringmarketplace (>=1.35.0,<1.36.0)"] +mgh = ["mypy-boto3-mgh (>=1.35.0,<1.36.0)"] +mgn = ["mypy-boto3-mgn (>=1.35.0,<1.36.0)"] +migration-hub-refactor-spaces = ["mypy-boto3-migration-hub-refactor-spaces (>=1.35.0,<1.36.0)"] +migrationhub-config = ["mypy-boto3-migrationhub-config (>=1.35.0,<1.36.0)"] +migrationhuborchestrator = ["mypy-boto3-migrationhuborchestrator (>=1.35.0,<1.36.0)"] +migrationhubstrategy = ["mypy-boto3-migrationhubstrategy (>=1.35.0,<1.36.0)"] +mq = ["mypy-boto3-mq (>=1.35.0,<1.36.0)"] +mturk = ["mypy-boto3-mturk (>=1.35.0,<1.36.0)"] +mwaa = ["mypy-boto3-mwaa (>=1.35.0,<1.36.0)"] +neptune = ["mypy-boto3-neptune (>=1.35.0,<1.36.0)"] +neptune-graph = ["mypy-boto3-neptune-graph (>=1.35.0,<1.36.0)"] +neptunedata = ["mypy-boto3-neptunedata (>=1.35.0,<1.36.0)"] +network-firewall = ["mypy-boto3-network-firewall (>=1.35.0,<1.36.0)"] +networkflowmonitor = ["mypy-boto3-networkflowmonitor (>=1.35.0,<1.36.0)"] +networkmanager = ["mypy-boto3-networkmanager (>=1.35.0,<1.36.0)"] +networkmonitor = ["mypy-boto3-networkmonitor (>=1.35.0,<1.36.0)"] +notifications = ["mypy-boto3-notifications (>=1.35.0,<1.36.0)"] +notificationscontacts = ["mypy-boto3-notificationscontacts (>=1.35.0,<1.36.0)"] +oam = ["mypy-boto3-oam (>=1.35.0,<1.36.0)"] +observabilityadmin = ["mypy-boto3-observabilityadmin (>=1.35.0,<1.36.0)"] +omics = ["mypy-boto3-omics (>=1.35.0,<1.36.0)"] +opensearch = ["mypy-boto3-opensearch (>=1.35.0,<1.36.0)"] +opensearchserverless = ["mypy-boto3-opensearchserverless (>=1.35.0,<1.36.0)"] +opsworks = ["mypy-boto3-opsworks (>=1.35.0,<1.36.0)"] +opsworkscm = ["mypy-boto3-opsworkscm (>=1.35.0,<1.36.0)"] +organizations = ["mypy-boto3-organizations (>=1.35.0,<1.36.0)"] +osis = ["mypy-boto3-osis (>=1.35.0,<1.36.0)"] +outposts = ["mypy-boto3-outposts (>=1.35.0,<1.36.0)"] +panorama = ["mypy-boto3-panorama (>=1.35.0,<1.36.0)"] +partnercentral-selling = ["mypy-boto3-partnercentral-selling (>=1.35.0,<1.36.0)"] +payment-cryptography = ["mypy-boto3-payment-cryptography (>=1.35.0,<1.36.0)"] +payment-cryptography-data = ["mypy-boto3-payment-cryptography-data (>=1.35.0,<1.36.0)"] +pca-connector-ad = ["mypy-boto3-pca-connector-ad (>=1.35.0,<1.36.0)"] +pca-connector-scep = ["mypy-boto3-pca-connector-scep (>=1.35.0,<1.36.0)"] +pcs = ["mypy-boto3-pcs (>=1.35.0,<1.36.0)"] +personalize = ["mypy-boto3-personalize (>=1.35.0,<1.36.0)"] +personalize-events = ["mypy-boto3-personalize-events (>=1.35.0,<1.36.0)"] +personalize-runtime = ["mypy-boto3-personalize-runtime (>=1.35.0,<1.36.0)"] +pi = ["mypy-boto3-pi (>=1.35.0,<1.36.0)"] +pinpoint = ["mypy-boto3-pinpoint (>=1.35.0,<1.36.0)"] +pinpoint-email = ["mypy-boto3-pinpoint-email (>=1.35.0,<1.36.0)"] +pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (>=1.35.0,<1.36.0)"] +pinpoint-sms-voice-v2 = ["mypy-boto3-pinpoint-sms-voice-v2 (>=1.35.0,<1.36.0)"] +pipes = ["mypy-boto3-pipes (>=1.35.0,<1.36.0)"] +polly = ["mypy-boto3-polly (>=1.35.0,<1.36.0)"] +pricing = ["mypy-boto3-pricing (>=1.35.0,<1.36.0)"] +privatenetworks = ["mypy-boto3-privatenetworks (>=1.35.0,<1.36.0)"] +proton = ["mypy-boto3-proton (>=1.35.0,<1.36.0)"] +qapps = ["mypy-boto3-qapps (>=1.35.0,<1.36.0)"] +qbusiness = ["mypy-boto3-qbusiness (>=1.35.0,<1.36.0)"] +qconnect = ["mypy-boto3-qconnect (>=1.35.0,<1.36.0)"] +qldb = ["mypy-boto3-qldb (>=1.35.0,<1.36.0)"] +qldb-session = ["mypy-boto3-qldb-session (>=1.35.0,<1.36.0)"] +quicksight = ["mypy-boto3-quicksight (>=1.35.0,<1.36.0)"] +ram = ["mypy-boto3-ram (>=1.35.0,<1.36.0)"] +rbin = ["mypy-boto3-rbin (>=1.35.0,<1.36.0)"] +rds = ["mypy-boto3-rds (>=1.35.0,<1.36.0)"] +rds-data = ["mypy-boto3-rds-data (>=1.35.0,<1.36.0)"] +redshift = ["mypy-boto3-redshift (>=1.35.0,<1.36.0)"] +redshift-data = ["mypy-boto3-redshift-data (>=1.35.0,<1.36.0)"] +redshift-serverless = ["mypy-boto3-redshift-serverless (>=1.35.0,<1.36.0)"] +rekognition = ["mypy-boto3-rekognition (>=1.35.0,<1.36.0)"] +repostspace = ["mypy-boto3-repostspace (>=1.35.0,<1.36.0)"] +resiliencehub = ["mypy-boto3-resiliencehub (>=1.35.0,<1.36.0)"] +resource-explorer-2 = ["mypy-boto3-resource-explorer-2 (>=1.35.0,<1.36.0)"] +resource-groups = ["mypy-boto3-resource-groups (>=1.35.0,<1.36.0)"] +resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (>=1.35.0,<1.36.0)"] +robomaker = ["mypy-boto3-robomaker (>=1.35.0,<1.36.0)"] +rolesanywhere = ["mypy-boto3-rolesanywhere (>=1.35.0,<1.36.0)"] +route53 = ["mypy-boto3-route53 (>=1.35.0,<1.36.0)"] +route53-recovery-cluster = ["mypy-boto3-route53-recovery-cluster (>=1.35.0,<1.36.0)"] +route53-recovery-control-config = ["mypy-boto3-route53-recovery-control-config (>=1.35.0,<1.36.0)"] +route53-recovery-readiness = ["mypy-boto3-route53-recovery-readiness (>=1.35.0,<1.36.0)"] +route53domains = ["mypy-boto3-route53domains (>=1.35.0,<1.36.0)"] +route53profiles = ["mypy-boto3-route53profiles (>=1.35.0,<1.36.0)"] +route53resolver = ["mypy-boto3-route53resolver (>=1.35.0,<1.36.0)"] +rum = ["mypy-boto3-rum (>=1.35.0,<1.36.0)"] +s3 = ["mypy-boto3-s3 (>=1.35.0,<1.36.0)"] +s3control = ["mypy-boto3-s3control (>=1.35.0,<1.36.0)"] +s3outposts = ["mypy-boto3-s3outposts (>=1.35.0,<1.36.0)"] +s3tables = ["mypy-boto3-s3tables (>=1.35.0,<1.36.0)"] +sagemaker = ["mypy-boto3-sagemaker (>=1.35.0,<1.36.0)"] +sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.35.0,<1.36.0)"] +sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.35.0,<1.36.0)"] +sagemaker-featurestore-runtime = ["mypy-boto3-sagemaker-featurestore-runtime (>=1.35.0,<1.36.0)"] +sagemaker-geospatial = ["mypy-boto3-sagemaker-geospatial (>=1.35.0,<1.36.0)"] +sagemaker-metrics = ["mypy-boto3-sagemaker-metrics (>=1.35.0,<1.36.0)"] +sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (>=1.35.0,<1.36.0)"] +savingsplans = ["mypy-boto3-savingsplans (>=1.35.0,<1.36.0)"] +scheduler = ["mypy-boto3-scheduler (>=1.35.0,<1.36.0)"] +schemas = ["mypy-boto3-schemas (>=1.35.0,<1.36.0)"] +sdb = ["mypy-boto3-sdb (>=1.35.0,<1.36.0)"] +secretsmanager = ["mypy-boto3-secretsmanager (>=1.35.0,<1.36.0)"] +security-ir = ["mypy-boto3-security-ir (>=1.35.0,<1.36.0)"] +securityhub = ["mypy-boto3-securityhub (>=1.35.0,<1.36.0)"] +securitylake = ["mypy-boto3-securitylake (>=1.35.0,<1.36.0)"] +serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.35.0,<1.36.0)"] +service-quotas = ["mypy-boto3-service-quotas (>=1.35.0,<1.36.0)"] +servicecatalog = ["mypy-boto3-servicecatalog (>=1.35.0,<1.36.0)"] +servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (>=1.35.0,<1.36.0)"] +servicediscovery = ["mypy-boto3-servicediscovery (>=1.35.0,<1.36.0)"] +ses = ["mypy-boto3-ses (>=1.35.0,<1.36.0)"] +sesv2 = ["mypy-boto3-sesv2 (>=1.35.0,<1.36.0)"] +shield = ["mypy-boto3-shield (>=1.35.0,<1.36.0)"] +signer = ["mypy-boto3-signer (>=1.35.0,<1.36.0)"] +simspaceweaver = ["mypy-boto3-simspaceweaver (>=1.35.0,<1.36.0)"] +sms = ["mypy-boto3-sms (>=1.35.0,<1.36.0)"] +sms-voice = ["mypy-boto3-sms-voice (>=1.35.0,<1.36.0)"] +snow-device-management = ["mypy-boto3-snow-device-management (>=1.35.0,<1.36.0)"] +snowball = ["mypy-boto3-snowball (>=1.35.0,<1.36.0)"] +sns = ["mypy-boto3-sns (>=1.35.0,<1.36.0)"] +socialmessaging = ["mypy-boto3-socialmessaging (>=1.35.0,<1.36.0)"] +sqs = ["mypy-boto3-sqs (>=1.35.0,<1.36.0)"] +ssm = ["mypy-boto3-ssm (>=1.35.0,<1.36.0)"] +ssm-contacts = ["mypy-boto3-ssm-contacts (>=1.35.0,<1.36.0)"] +ssm-incidents = ["mypy-boto3-ssm-incidents (>=1.35.0,<1.36.0)"] +ssm-quicksetup = ["mypy-boto3-ssm-quicksetup (>=1.35.0,<1.36.0)"] +ssm-sap = ["mypy-boto3-ssm-sap (>=1.35.0,<1.36.0)"] +sso = ["mypy-boto3-sso (>=1.35.0,<1.36.0)"] +sso-admin = ["mypy-boto3-sso-admin (>=1.35.0,<1.36.0)"] +sso-oidc = ["mypy-boto3-sso-oidc (>=1.35.0,<1.36.0)"] +stepfunctions = ["mypy-boto3-stepfunctions (>=1.35.0,<1.36.0)"] +storagegateway = ["mypy-boto3-storagegateway (>=1.35.0,<1.36.0)"] +sts = ["mypy-boto3-sts (>=1.35.0,<1.36.0)"] +supplychain = ["mypy-boto3-supplychain (>=1.35.0,<1.36.0)"] +support = ["mypy-boto3-support (>=1.35.0,<1.36.0)"] +support-app = ["mypy-boto3-support-app (>=1.35.0,<1.36.0)"] +swf = ["mypy-boto3-swf (>=1.35.0,<1.36.0)"] +synthetics = ["mypy-boto3-synthetics (>=1.35.0,<1.36.0)"] +taxsettings = ["mypy-boto3-taxsettings (>=1.35.0,<1.36.0)"] +textract = ["mypy-boto3-textract (>=1.35.0,<1.36.0)"] +timestream-influxdb = ["mypy-boto3-timestream-influxdb (>=1.35.0,<1.36.0)"] +timestream-query = ["mypy-boto3-timestream-query (>=1.35.0,<1.36.0)"] +timestream-write = ["mypy-boto3-timestream-write (>=1.35.0,<1.36.0)"] +tnb = ["mypy-boto3-tnb (>=1.35.0,<1.36.0)"] +transcribe = ["mypy-boto3-transcribe (>=1.35.0,<1.36.0)"] +transfer = ["mypy-boto3-transfer (>=1.35.0,<1.36.0)"] +translate = ["mypy-boto3-translate (>=1.35.0,<1.36.0)"] +trustedadvisor = ["mypy-boto3-trustedadvisor (>=1.35.0,<1.36.0)"] +verifiedpermissions = ["mypy-boto3-verifiedpermissions (>=1.35.0,<1.36.0)"] +voice-id = ["mypy-boto3-voice-id (>=1.35.0,<1.36.0)"] +vpc-lattice = ["mypy-boto3-vpc-lattice (>=1.35.0,<1.36.0)"] +waf = ["mypy-boto3-waf (>=1.35.0,<1.36.0)"] +waf-regional = ["mypy-boto3-waf-regional (>=1.35.0,<1.36.0)"] +wafv2 = ["mypy-boto3-wafv2 (>=1.35.0,<1.36.0)"] +wellarchitected = ["mypy-boto3-wellarchitected (>=1.35.0,<1.36.0)"] +wisdom = ["mypy-boto3-wisdom (>=1.35.0,<1.36.0)"] +workdocs = ["mypy-boto3-workdocs (>=1.35.0,<1.36.0)"] +workmail = ["mypy-boto3-workmail (>=1.35.0,<1.36.0)"] +workmailmessageflow = ["mypy-boto3-workmailmessageflow (>=1.35.0,<1.36.0)"] +workspaces = ["mypy-boto3-workspaces (>=1.35.0,<1.36.0)"] +workspaces-thin-client = ["mypy-boto3-workspaces-thin-client (>=1.35.0,<1.36.0)"] +workspaces-web = ["mypy-boto3-workspaces-web (>=1.35.0,<1.36.0)"] +xray = ["mypy-boto3-xray (>=1.35.0,<1.36.0)"] + +[[package]] +name = "botocore" +version = "1.35.91" +description = "Low-level, data-driven core of boto 3." +optional = false +python-versions = ">=3.8" +files = [ + {file = "botocore-1.35.91-py3-none-any.whl", hash = "sha256:93de9d0f52f7e36a2c190d55520d3b2654f32c5a628fdd484bffa00bc7865e1d"}, + {file = "botocore-1.35.91.tar.gz", hash = "sha256:7b0b9c5954701fff4d2c516918f45641b04ff4ca92bbd9f5b37c0b80f8c14220"}, +] + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} + +[package.extras] +crt = ["awscrt (==0.22.0)"] + +[[package]] +name = "botocore-stubs" +version = "1.35.90" +description = "Type annotations and code completion for botocore" +optional = false +python-versions = ">=3.8" +files = [ + {file = "botocore_stubs-1.35.90-py3-none-any.whl", hash = "sha256:f7fd78d84f49d28692662b9bdeb4c92f1bf8a5707d0c28c8544399005b02823b"}, + {file = "botocore_stubs-1.35.90.tar.gz", hash = "sha256:c6b294cae436eaaf87dcb717e4348c250ea1fc170336579da114b693663d8e42"}, +] + +[package.dependencies] +types-awscrt = "*" + +[package.extras] +botocore = ["botocore"] + [[package]] name = "certifi" version = "2024.7.4" @@ -1008,6 +1491,17 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + [[package]] name = "jsonschema" version = "4.23.0" @@ -1253,6 +1747,20 @@ install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] +[[package]] +name = "mypy-boto3-s3" +version = "1.35.81" +description = "Type annotations for boto3 S3 1.35.81 service generated with mypy-boto3-builder 8.6.4" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy_boto3_s3-1.35.81-py3-none-any.whl", hash = "sha256:6af1d815ff2cc8e32ca1190c7387f94341c1607444f958ac283aa10b1d11db08"}, + {file = "mypy_boto3_s3-1.35.81.tar.gz", hash = "sha256:fe1a6860c0ca7016e24089819433c0d5835d4a57635bb42628645b71271b946c"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.12\""} + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -2283,6 +2791,23 @@ files = [ {file = "ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3"}, ] +[[package]] +name = "s3transfer" +version = "0.10.4" +description = "An Amazon S3 Transfer Manager" +optional = false +python-versions = ">=3.8" +files = [ + {file = "s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e"}, + {file = "s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7"}, +] + +[package.dependencies] +botocore = ">=1.33.2,<2.0a.0" + +[package.extras] +crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] + [[package]] name = "secretstorage" version = "3.3.3" @@ -2481,6 +3006,17 @@ rich = ">=10.11.0" shellingham = ">=1.3.0" typing-extensions = ">=3.7.4.3" +[[package]] +name = "types-awscrt" +version = "0.23.6" +description = "Type annotations and code completion for awscrt" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types_awscrt-0.23.6-py3-none-any.whl", hash = "sha256:fbf9c221af5607b24bf17f8431217ce8b9a27917139edbc984891eb63fd5a593"}, + {file = "types_awscrt-0.23.6.tar.gz", hash = "sha256:405bce8c281f9e7c6c92a229225cc0bf10d30729a6a601123213389bd524b8b1"}, +] + [[package]] name = "types-protobuf" version = "5.29.1.20241207" @@ -2528,6 +3064,17 @@ files = [ [package.dependencies] urllib3 = ">=2" +[[package]] +name = "types-s3transfer" +version = "0.10.4" +description = "Type annotations and code completion for s3transfer" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types_s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:22ac1aabc98f9d7f2928eb3fb4d5c02bf7435687f0913345a97dd3b84d0c217d"}, + {file = "types_s3transfer-0.10.4.tar.gz", hash = "sha256:03123477e3064c81efe712bf9d372c7c72f2790711431f9baa59cf96ea607267"}, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -2632,4 +3179,4 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-it [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.13" -content-hash = "215e53ad4d91f85a7ff2682c585005e64d7ad0143f6c29489e2fb173a3cd5ca0" +content-hash = "c1c4f7493b13cbcd1e96ccb5e9c5f75c2bd2c91271211e1b0db133d7e70a9e49" diff --git a/pyproject.toml b/pyproject.toml index e3571031..5df97291 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,9 +47,11 @@ packages = [ {include = "settings.py"} ] readme = "README.md" -version = "0.10.2" +version = "0.11.0" [tool.poetry.dependencies] +boto3 = "^1.35.88" +boto3-stubs = {extras = ["s3"], version = "^1.35.88"} cookiecutter = "*" cron-converter = "^1.2.1" deprecation = "^2.1.0" diff --git a/settings.py b/settings.py index abd04fe7..16730f4a 100644 --- a/settings.py +++ b/settings.py @@ -11,7 +11,7 @@ ENV = os.getenv("ENV", "development") IS_PRODUCTION = ENV == "production" IS_TESTING = env_to_bool("IS_TESTING", "pytest" in sys.argv[0] or sys.argv[0] == "-c") - +CUSTOMER_IDENTIFIER = os.getenv("CUSTOMER_IDENTIFIER", "undefined") INTEGRATION_TEST_URL = os.getenv("INTEGRATION_TEST_URL") INTEGRATION_TEST_CLIENT_ID = os.getenv("INTEGRATION_TEST_CLIENT_ID")