diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml
index 8402ff66d2e..2e799c65333 100644
--- a/.github/workflows/auto-merge.yml
+++ b/.github/workflows/auto-merge.yml
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Dependabot metadata
id: metadata
- uses: dependabot/fetch-metadata@v1.3.5
+ uses: dependabot/fetch-metadata@v1.3.6
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
- name: Enable auto-merge for mypy-boto3 stubs Dependabot PRs
diff --git a/.github/workflows/publish_v2_layer.yml b/.github/workflows/publish_v2_layer.yml
index 96f25cd9dd8..b3e6f143dc5 100644
--- a/.github/workflows/publish_v2_layer.yml
+++ b/.github/workflows/publish_v2_layer.yml
@@ -65,7 +65,7 @@ jobs:
# NOTE: we need QEMU to build Layer against a different architecture (e.g., ARM)
- name: Set up Docker Buildx
id: builder
- uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # v2.0.0
+ uses: docker/setup-buildx-action@15c905b16b06416d2086efa066dd8e3a35cc7f98 # v2.4.0
with:
install: true
driver: docker
diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml
index 06196b97f92..7a8fb00ebbe 100644
--- a/.github/workflows/run-e2e-tests.yml
+++ b/.github/workflows/run-e2e-tests.yml
@@ -26,6 +26,7 @@ jobs:
id-token: write # needed to request JWT with GitHub's OIDC Token endpoint. docs: https://bit.ly/3MNgQO9
contents: read
strategy:
+ fail-fast: false # needed so if a version fails, the others will still be able to complete and cleanup
matrix:
version: ["3.7", "3.8", "3.9"]
if: ${{ github.actor != 'dependabot[bot]' }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6df040df4ab..bde94fa2806 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,42 @@
## Bug Fixes
+* parallel_run should fail when e2e tests fail
+* bump aws-cdk version
+* **ci:** scope e2e tests by python version
+* **ci:** add auth to API HTTP Gateway and Lambda Function Url ([#1882](https://github.com/awslabs/aws-lambda-powertools-python/issues/1882))
+* **license:** correction to MIT + MIT-0 (no proprietary anymore) ([#1883](https://github.com/awslabs/aws-lambda-powertools-python/issues/1883))
+* **license:** add MIT-0 license header ([#1871](https://github.com/awslabs/aws-lambda-powertools-python/issues/1871))
+* **tests:** make logs fetching more robust ([#1878](https://github.com/awslabs/aws-lambda-powertools-python/issues/1878))
+* **tests:** remove custom workers
+* **tests:** make sure multiple e2e tests run concurrently ([#1861](https://github.com/awslabs/aws-lambda-powertools-python/issues/1861))
+
+## Documentation
+
+* **event-source:** fix incorrect method in example CloudWatch Logs ([#1857](https://github.com/awslabs/aws-lambda-powertools-python/issues/1857))
+* **homepage:** add banner for end-of-support v1 ([#1879](https://github.com/awslabs/aws-lambda-powertools-python/issues/1879))
+* **parameters:** snippets split, improved, and lint ([#1564](https://github.com/awslabs/aws-lambda-powertools-python/issues/1564))
+
+## Maintenance
+
+* **deps:** bump docker/setup-buildx-action from 2.0.0 to 2.4.0 ([#1873](https://github.com/awslabs/aws-lambda-powertools-python/issues/1873))
+* **deps:** bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 ([#1855](https://github.com/awslabs/aws-lambda-powertools-python/issues/1855))
+* **deps-dev:** bump flake8-bugbear from 22.12.6 to 23.1.20 ([#1854](https://github.com/awslabs/aws-lambda-powertools-python/issues/1854))
+* **deps-dev:** bump mkdocs-material from 9.0.6 to 9.0.8 ([#1874](https://github.com/awslabs/aws-lambda-powertools-python/issues/1874))
+* **deps-dev:** bump isort from 5.11.4 to 5.11.5 ([#1875](https://github.com/awslabs/aws-lambda-powertools-python/issues/1875))
+* **deps-dev:** bump mypy-boto3-s3 from 1.26.0.post1 to 1.26.58 ([#1868](https://github.com/awslabs/aws-lambda-powertools-python/issues/1868))
+* **deps-dev:** bump aws-cdk-lib from 2.62.0 to 2.62.1 ([#1866](https://github.com/awslabs/aws-lambda-powertools-python/issues/1866))
+* **deps-dev:** bump mypy-boto3-cloudformation from 1.26.35.post1 to 1.26.57 ([#1865](https://github.com/awslabs/aws-lambda-powertools-python/issues/1865))
+* **deps-dev:** bump coverage from 7.0.5 to 7.1.0 ([#1862](https://github.com/awslabs/aws-lambda-powertools-python/issues/1862))
+* **deps-dev:** bump aws-cdk-lib from 2.61.1 to 2.62.0 ([#1863](https://github.com/awslabs/aws-lambda-powertools-python/issues/1863))
+* **deps-dev:** bump aws-cdk-lib from 2.62.1 to 2.62.2 ([#1869](https://github.com/awslabs/aws-lambda-powertools-python/issues/1869))
+* **deps-dev:** bump mypy-boto3-lambda from 1.26.49 to 1.26.55 ([#1856](https://github.com/awslabs/aws-lambda-powertools-python/issues/1856))
+
+
+
+## [v2.7.0] - 2023-01-24
+## Bug Fixes
+
* git-chlg docker image is broken
## Features
@@ -14,16 +50,17 @@
## Maintenance
+* update v2 layer ARN on documentation
* **deps:** bump peaceiris/actions-gh-pages from 3.9.1 to 3.9.2 ([#1841](https://github.com/awslabs/aws-lambda-powertools-python/issues/1841))
* **deps:** bump future from 0.18.2 to 0.18.3 ([#1836](https://github.com/awslabs/aws-lambda-powertools-python/issues/1836))
* **deps:** bump zgosalvez/github-actions-ensure-sha-pinned-actions from 2.0.4 to 2.0.5 ([#1837](https://github.com/awslabs/aws-lambda-powertools-python/issues/1837))
-* **deps-dev:** bump mkdocs-material from 9.0.5 to 9.0.6 ([#1851](https://github.com/awslabs/aws-lambda-powertools-python/issues/1851))
+* **deps-dev:** bump mkdocs-material from 9.0.4 to 9.0.5 ([#1840](https://github.com/awslabs/aws-lambda-powertools-python/issues/1840))
* **deps-dev:** bump types-requests from 2.28.11.7 to 2.28.11.8 ([#1843](https://github.com/awslabs/aws-lambda-powertools-python/issues/1843))
* **deps-dev:** bump mypy-boto3-cloudwatch from 1.26.30 to 1.26.52 ([#1847](https://github.com/awslabs/aws-lambda-powertools-python/issues/1847))
* **deps-dev:** bump pytest from 7.2.0 to 7.2.1 ([#1838](https://github.com/awslabs/aws-lambda-powertools-python/issues/1838))
-* **deps-dev:** bump mkdocs-material from 9.0.4 to 9.0.5 ([#1840](https://github.com/awslabs/aws-lambda-powertools-python/issues/1840))
* **deps-dev:** bump aws-cdk-lib from 2.60.0 to 2.61.1 ([#1849](https://github.com/awslabs/aws-lambda-powertools-python/issues/1849))
* **deps-dev:** bump mypy-boto3-logs from 1.26.49 to 1.26.53 ([#1850](https://github.com/awslabs/aws-lambda-powertools-python/issues/1850))
+* **deps-dev:** bump mkdocs-material from 9.0.5 to 9.0.6 ([#1851](https://github.com/awslabs/aws-lambda-powertools-python/issues/1851))
* **deps-dev:** bump mkdocs-material from 9.0.3 to 9.0.4 ([#1833](https://github.com/awslabs/aws-lambda-powertools-python/issues/1833))
* **deps-dev:** bump mypy-boto3-logs from 1.26.43 to 1.26.49 ([#1834](https://github.com/awslabs/aws-lambda-powertools-python/issues/1834))
* **deps-dev:** bump mypy-boto3-secretsmanager from 1.26.40 to 1.26.49 ([#1835](https://github.com/awslabs/aws-lambda-powertools-python/issues/1835))
@@ -2778,7 +2815,8 @@
* Merge pull request [#5](https://github.com/awslabs/aws-lambda-powertools-python/issues/5) from jfuss/feat/python38
-[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.6.0...HEAD
+[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.7.0...HEAD
+[v2.7.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.6.0...v2.7.0
[v2.6.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.5.0...v2.6.0
[v2.5.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.4.0...v2.5.0
[v2.4.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v2.3.1...v2.4.0
diff --git a/LICENSE b/LICENSE
index 9e30e05ab6d..fcdede53dc8 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,5 @@
+MIT No Attribution
+
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
diff --git a/docs/index.md b/docs/index.md
index 58e4322da00..36b6906ceb3 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -26,8 +26,8 @@ A suite of utilities for AWS Lambda functions to ease adopting best practices su
Powertools is available in the following formats:
-* **Lambda Layer (x86_64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19**](#){: .copyMe}:clipboard:
-* **Lambda Layer (arm64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19**](#){: .copyMe}:clipboard:
+* **Lambda Layer (x86_64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20**](#){: .copyMe}:clipboard:
+* **Lambda Layer (arm64)**: [**arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20**](#){: .copyMe}:clipboard:
* **PyPi**: **`pip install "aws-lambda-powertools"`**
???+ info "Some utilities require additional dependencies"
@@ -67,55 +67,55 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
| Region | Layer ARN |
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
- | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
- | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:19](#){: .copyMe}:clipboard: |
+ | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
+ | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:20](#){: .copyMe}:clipboard: |
=== "arm64"
| Region | Layer ARN |
| ---------------- | ---------------------------------------------------------------------------------------------------------------- |
- | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
- | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19](#){: .copyMe}:clipboard: |
+ | `af-south-1` | [arn:aws:lambda:af-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-east-1` | [arn:aws:lambda:ap-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-south-1` | [arn:aws:lambda:ap-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `ca-central-1` | [arn:aws:lambda:ca-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-central-1` | [arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-north-1` | [arn:aws:lambda:eu-north-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-south-1` | [arn:aws:lambda:eu-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-west-1` | [arn:aws:lambda:eu-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-west-2` | [arn:aws:lambda:eu-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `eu-west-3` | [arn:aws:lambda:eu-west-3:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `me-south-1` | [arn:aws:lambda:me-south-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `sa-east-1` | [arn:aws:lambda:sa-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `us-east-1` | [arn:aws:lambda:us-east-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `us-east-2` | [arn:aws:lambda:us-east-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `us-west-1` | [arn:aws:lambda:us-west-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
+ | `us-west-2` | [arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20](#){: .copyMe}:clipboard: |
??? note "Note: Click to expand and copy code snippets for popular frameworks"
@@ -128,7 +128,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
Type: AWS::Serverless::Function
Properties:
Layers:
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20
```
=== "Serverless framework"
@@ -138,7 +138,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
hello:
handler: lambda_function.lambda_handler
layers:
- - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19
+ - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20
```
=== "CDK"
@@ -154,7 +154,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn(
self,
id="lambda-powertools",
- layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19"
+ layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20"
)
aws_lambda.Function(self,
'sample-app-lambda',
@@ -203,7 +203,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
role = aws_iam_role.iam_for_lambda.arn
handler = "index.test"
runtime = "python3.9"
- layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19"]
+ layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20"]
source_code_hash = filebase64sha256("lambda_function_payload.zip")
}
@@ -256,7 +256,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
? Do you want to configure advanced settings? Yes
...
? Do you want to enable Lambda layers for this function? Yes
- ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19
+ ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20
❯ amplify push -y
@@ -267,7 +267,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
- Name:
? Which setting do you want to update? Lambda layers configuration
? Do you want to enable Lambda layers for this function? Yes
- ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:19
+ ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:20
? Do you want to edit the local lambda function now? No
```
@@ -276,7 +276,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
Change {region} to your AWS region, e.g. `eu-west-1`
```bash title="AWS CLI"
- aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:19 --region {region}
+ aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2:20 --region {region}
```
The pre-signed URL to download this Lambda Layer will be within `Location` key.
@@ -291,7 +291,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
Properties:
Architectures: [arm64]
Layers:
- - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19
+ - !Sub arn:aws:lambda:${AWS::Region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20
```
=== "Serverless framework"
@@ -302,7 +302,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
handler: lambda_function.lambda_handler
architecture: arm64
layers:
- - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19
+ - arn:aws:lambda:${aws:region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20
```
=== "CDK"
@@ -318,7 +318,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
powertools_layer = aws_lambda.LayerVersion.from_layer_version_arn(
self,
id="lambda-powertools",
- layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19"
+ layer_version_arn=f"arn:aws:lambda:{env.region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20"
)
aws_lambda.Function(self,
'sample-app-lambda',
@@ -368,7 +368,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
role = aws_iam_role.iam_for_lambda.arn
handler = "index.test"
runtime = "python3.9"
- layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19"]
+ layers = ["arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20"]
architectures = ["arm64"]
source_code_hash = filebase64sha256("lambda_function_payload.zip")
@@ -424,7 +424,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
? Do you want to configure advanced settings? Yes
...
? Do you want to enable Lambda layers for this function? Yes
- ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19
+ ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20
❯ amplify push -y
@@ -435,7 +435,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
- Name:
? Which setting do you want to update? Lambda layers configuration
? Do you want to enable Lambda layers for this function? Yes
- ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19
+ ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20
? Do you want to edit the local lambda function now? No
```
@@ -443,7 +443,7 @@ You can include Powertools Lambda Layer using [AWS Lambda Console](https://docs.
Change {region} to your AWS region, e.g. `eu-west-1`
```bash title="AWS CLI"
- aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:19 --region {region}
+ aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV2-Arm64:20 --region {region}
```
The pre-signed URL to download this Lambda Layer will be within `Location` key.
diff --git a/docs/overrides/main.html b/docs/overrides/main.html
index 0af326afb24..10b02d3a905 100644
--- a/docs/overrides/main.html
+++ b/docs/overrides/main.html
@@ -1,5 +1,10 @@
{% extends "base.html" %}
+{% block announce %}
+👋 Powertools for Python v1 will no longer receive updates or releases after 31/03/2023!
+We encourage you to read our upgrade guide on how to migrate to v2.
+{% endblock %}
+
{% block outdated %}
You're not viewing the latest version.
diff --git a/docs/upgrade.md b/docs/upgrade.md
index e16acded572..369daca1832 100644
--- a/docs/upgrade.md
+++ b/docs/upgrade.md
@@ -5,6 +5,12 @@ description: Guide to update between major Powertools versions
+## End of support v1
+
+On March 31st, AWS Lambda Powertools for Python v1 will reach end of support. After that, Powertools v1 will no longer receive updates or releases. If you are still using v1, we encourage you to read our upgrade guide and update to the latest version.
+
+Given our commitment to all of our customers using AWS Lambda Powertools for Python, we will keep [Pypi](https://pypi.org/project/aws-lambda-powertools/) v1 releases and documentation 1.x versions to prevent any disruption.
+
## Migrate to v2 from v1
We've made minimal breaking changes to make your transition to v2 as smooth as possible.
diff --git a/docs/utilities/data_classes.md b/docs/utilities/data_classes.md
index 85c58e7ce72..cd02f6e8971 100644
--- a/docs/utilities/data_classes.md
+++ b/docs/utilities/data_classes.md
@@ -491,7 +491,7 @@ decompress and parse json data from the event.
@event_source(data_class=CloudWatchLogsEvent)
def lambda_handler(event: CloudWatchLogsEvent, context):
- decompressed_log: CloudWatchLogsDecodedData = event.parse_logs_data
+ decompressed_log: CloudWatchLogsDecodedData = event.parse_logs_data()
log_events = decompressed_log.log_events
for event in log_events:
do_something_with(event.timestamp, event.message)
diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md
index 9441d94fe12..d021ae44a61 100644
--- a/docs/utilities/parameters.md
+++ b/docs/utilities/parameters.md
@@ -15,6 +15,9 @@ The parameters utility provides high-level functions to retrieve one or multiple
## Getting started
+???+ tip
+ All examples shared in this documentation are available within the [project repository](https://github.com/awslabs/aws-lambda-powertools-python/tree/develop/examples){target="_blank"}.
+
By default, we fetch parameters from System Manager Parameter Store, secrets from Secrets Manager, and application configuration from AppConfig.
### IAM Permissions
@@ -37,54 +40,26 @@ This utility requires additional permissions to work as expected.
### Fetching parameters
-You can retrieve a single parameter using `get_parameter` high-level function.
-
-```python hl_lines="5" title="Fetching a single parameter"
-from aws_lambda_powertools.utilities import parameters
+You can retrieve a single parameter using the `get_parameter` high-level function.
-def handler(event, context):
- # Retrieve a single parameter
- value = parameters.get_parameter("/my/parameter")
-
-```
+=== "getting_started_single_ssm_parameter.py"
+ ```python hl_lines="3 10"
+ --8<-- "examples/parameters/src/getting_started_single_ssm_parameter.py"
+ ```
For multiple parameters, you can use either:
* `get_parameters` to recursively fetch all parameters by path.
* `get_parameters_by_name` to fetch distinct parameters by their full name. It also accepts custom caching, transform, decrypt per parameter.
-=== "get_parameters"
-
- ```python hl_lines="1 6"
- from aws_lambda_powertools.utilities import parameters
-
- def handler(event, context):
- # Retrieve multiple parameters from a path prefix recursively
- # This returns a dict with the parameter name as key
- values = parameters.get_parameters("/my/path/prefix")
- for parameter, value in values.items():
- print(f"{parameter}: {value}")
+=== "getting_started_recursive_ssm_parameter.py"
+ ```python hl_lines="3 10 13"
+ --8<-- "examples/parameters/src/getting_started_recursive_ssm_parameter.py"
```
-=== "get_parameters_by_name"
-
- ```python hl_lines="3 5 14"
- from typing import Any
-
- from aws_lambda_powertools.utilities import get_parameters_by_name
-
- parameters = {
- "/develop/service/commons/telemetry/config": {"max_age": 300, "transform": "json"},
- "/no_cache_param": {"max_age": 0},
- # inherit default values
- "/develop/service/payment/api/capture/url": {},
- }
-
- def handler(event, context):
- # This returns a dict with the parameter name as key
- response: dict[str, Any] = parameters.get_parameters_by_name(parameters=parameters, max_age=60)
- for parameter, value in response.items():
- print(f"{parameter}: {value}")
+=== "getting_started_parameter_by_name.py"
+ ```python hl_lines="3 14"
+ --8<-- "examples/parameters/src/getting_started_parameter_by_name.py"
```
???+ tip "`get_parameters_by_name` supports graceful error handling"
@@ -96,40 +71,19 @@ For multiple parameters, you can use either:
* Keep only successful parameter names and their values in the response
* Raise `GetParameterError` if any of your parameters is named `_errors`
-```python hl_lines="3 5 12-13 15" title="Graceful error handling"
-from typing import Any
-
-from aws_lambda_powertools.utilities import get_parameters_by_name
-
-parameters = {
- "/develop/service/commons/telemetry/config": {"max_age": 300, "transform": "json"},
- # it would fail by default
- "/this/param/does/not/exist"
-}
-
-def handler(event, context):
- values: dict[str, Any] = parameters.get_parameters_by_name(parameters=parameters, raise_on_error=False)
- errors: list[str] = values.get("_errors", [])
-
- # Handle gracefully, since '/this/param/does/not/exist' will only be available in `_errors`
- if errors:
- ...
-
- for parameter, value in values.items():
- print(f"{parameter}: {value}")
-```
+=== "get_parameter_by_name_error_handling.py"
+ ```python hl_lines="3 5 12-13 15"
+ --8<-- "examples/parameters/src/get_parameter_by_name_error_handling.py"
+ ```
### Fetching secrets
-You can fetch secrets stored in Secrets Manager using `get_secrets`.
+You can fetch secrets stored in Secrets Manager using `get_secret`.
-```python hl_lines="1 5" title="Fetching secrets"
-from aws_lambda_powertools.utilities import parameters
-
-def handler(event, context):
- # Retrieve a single secret
- value = parameters.get_secret("my-secret")
-```
+=== "getting_started_secret.py"
+ ```python hl_lines="5 15"
+ --8<-- "examples/parameters/src/getting_started_secret.py"
+ ```
### Fetching app configurations
@@ -137,79 +91,84 @@ You can fetch application configurations in AWS AppConfig using `get_app_config`
The following will retrieve the latest version and store it in the cache.
-```python hl_lines="1 5" title="Fetching latest config from AppConfig"
-from aws_lambda_powertools.utilities import parameters
-
-def handler(event, context):
- # Retrieve a single configuration, latest version
- value: bytes = parameters.get_app_config(name="my_configuration", environment="my_env", application="my_app")
-```
+=== "getting_started_appconfig.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/getting_started_appconfig.py"
+ ```
## Advanced
### Adjusting cache TTL
???+ tip
- `max_age` parameter is also available in high level functions like `get_parameter`, `get_secret`, etc.
+ `max_age` parameter is also available in underlying provider functions like `get()`, `get_multiple()`, etc.
By default, we cache parameters retrieved in-memory for 5 seconds.
-You can adjust how long we should keep values in cache by using the param `max_age`, when using `get()` or `get_multiple()` methods across all providers.
+You can adjust how long we should keep values in cache by using the param `max_age`, when using `get_parameter()`, `get_parameters()` and `get_secret()` methods across all providers.
-```python hl_lines="9" title="Caching parameter(s) value in memory for longer than 5 seconds"
-from aws_lambda_powertools.utilities import parameters
-from botocore.config import Config
+=== "single_ssm_parameter_with_cache.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/single_ssm_parameter_with_cache.py"
+ ```
-config = Config(region_name="us-west-1")
-ssm_provider = parameters.SSMProvider(config=config)
+=== "recursive_ssm_parameter_with_cache.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/recursive_ssm_parameter_with_cache.py"
+ ```
-def handler(event, context):
- # Retrieve a single parameter
- value = ssm_provider.get("/my/parameter", max_age=60) # 1 minute
+=== "secret_with_cache.py"
+ ```python hl_lines="5 15"
+ --8<-- "examples/parameters/src/secret_with_cache.py"
+ ```
- # Retrieve multiple parameters from a path prefix
- values = ssm_provider.get_multiple("/my/path/prefix", max_age=60)
- for k, v in values.items():
- print(f"{k}: {v}")
-```
+=== "appconfig_with_cache.py"
+ ```python hl_lines="5 12-14"
+ --8<-- "examples/parameters/src/appconfig_with_cache.py"
+ ```
### Always fetching the latest
If you'd like to always ensure you fetch the latest parameter from the store regardless if already available in cache, use `force_fetch` param.
-```python hl_lines="5" title="Forcefully fetching the latest parameter whether TTL has expired or not"
-from aws_lambda_powertools.utilities import parameters
+=== "single_ssm_parameter_force_fetch.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/single_ssm_parameter_force_fetch.py"
+ ```
-def handler(event, context):
- # Retrieve a single parameter
- value = parameters.get_parameter("/my/parameter", force_fetch=True)
-```
+=== "recursive_ssm_parameter_force_fetch.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/recursive_ssm_parameter_force_fetch.py"
+ ```
+
+=== "secret_force_fetch.py"
+ ```python hl_lines="5 15"
+ --8<-- "examples/parameters/src/secret_force_fetch.py"
+ ```
+
+=== "appconfig_force_fetch.py"
+ ```python hl_lines="5 12-14"
+ --8<-- "examples/parameters/src/appconfig_force_fetch.py"
+ ```
### Built-in provider class
For greater flexibility such as configuring the underlying SDK client used by built-in providers, you can use their respective Provider Classes directly.
???+ tip
- This can be used to retrieve values from other regions, change the retry behavior, etc.
+ This is useful when you need to customize parameters for the SDK client, such as region, credentials, retries and others. For more information, read [botocore.config](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) and [boto3.session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html#module-boto3.session).
#### SSMProvider
-```python hl_lines="5 9 12" title="Example with SSMProvider for further extensibility"
-from aws_lambda_powertools.utilities import parameters
-from botocore.config import Config
-
-config = Config(region_name="us-west-1")
-ssm_provider = parameters.SSMProvider(config=config) # or boto3_session=boto3.Session()
-
-def handler(event, context):
- # Retrieve a single parameter
- value = ssm_provider.get("/my/parameter")
+=== "builtin_provider_ssm_single_parameter.py"
+ ```python hl_lines="6 11 12"
+ --8<-- "examples/parameters/src/builtin_provider_ssm_single_parameter.py"
+ ```
- # Retrieve multiple parameters from a path prefix
- values = ssm_provider.get_multiple("/my/path/prefix")
- for k, v in values.items():
- print(f"{k}: {v}")
-```
+=== "builtin_provider_ssm_recursive_parameter.py"
+ ```python hl_lines="6 19-25"
+ --8<-- "examples/parameters/src/builtin_provider_ssm_recursive_parameter.py"
+ ```
The AWS Systems Manager Parameter Store provider supports two additional arguments for the `get()` and `get_multiple()` methods:
@@ -218,30 +177,24 @@ The AWS Systems Manager Parameter Store provider supports two additional argumen
| **decrypt** | `False` | Will automatically decrypt the parameter. |
| **recursive** | `True` | For `get_multiple()` only, will fetch all parameter values recursively based on a path prefix. |
-```python hl_lines="6 8" title="Example with get() and get_multiple()"
-from aws_lambda_powertools.utilities import parameters
-
-ssm_provider = parameters.SSMProvider()
+You can create `SecureString` parameters, which are parameters that have a plaintext parameter name and an encrypted parameter value. If you don't use the `decrypt` argument, you will get an encrypted value. Read [here](https://docs.aws.amazon.com/kms/latest/developerguide/services-parameter-store.html) about best practices using KMS to secure your parameters.
-def handler(event, context):
- decrypted_value = ssm_provider.get("/my/encrypted/parameter", decrypt=True)
+=== "builtin_provider_ssm_with_decrypt.py"
+ ```python hl_lines="6 10 16"
+ --8<-- "examples/parameters/src/builtin_provider_ssm_with_decrypt.py"
+ ```
- no_recursive_values = ssm_provider.get_multiple("/my/path/prefix", recursive=False)
-```
+=== "builtin_provider_ssm_with_no_recursive.py"
+ ```python hl_lines="5 8 21"
+ --8<-- "examples/parameters/src/builtin_provider_ssm_with_no_recursive.py"
+ ```
#### SecretsProvider
-```python hl_lines="5 9" title="Example with SecretsProvider for further extensibility"
-from aws_lambda_powertools.utilities import parameters
-from botocore.config import Config
-
-config = Config(region_name="us-west-1")
-secrets_provider = parameters.SecretsProvider(config=config)
-
-def handler(event, context):
- # Retrieve a single secret
- value = secrets_provider.get("my-secret")
-```
+=== "builtin_provider_secret.py"
+ ```python hl_lines="4 6 9"
+ --8<-- "examples/parameters/src/builtin_provider_secret.py"
+ ```
#### DynamoDBProvider
@@ -261,25 +214,22 @@ For single parameters, you must use `id` as the [partition key](https://docs.aws
With this table, `dynamodb_provider.get("my-param")` will return `my-value`.
-=== "app.py"
- ```python hl_lines="3 7"
- from aws_lambda_powertools.utilities import parameters
-
- dynamodb_provider = parameters.DynamoDBProvider(table_name="my-table")
-
- def handler(event, context):
- # Retrieve a value from DynamoDB
- value = dynamodb_provider.get("my-parameter")
- ```
+=== "builtin_provider_dynamodb_single_parameter.py"
+ ```python hl_lines="5 8 15"
+ --8<-- "examples/parameters/src/builtin_provider_dynamodb_single_parameter.py"
+ ```
-=== "DynamoDB Local example"
- You can initialize the DynamoDB provider pointing to [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) using `endpoint_url` parameter:
+=== "sam_dynamodb_table_single.yaml"
+ ```yaml hl_lines="12-14"
+ --8<-- "examples/parameters/sam/sam_dynamodb_table_single.yaml"
+ ```
- ```python hl_lines="3"
- from aws_lambda_powertools.utilities import parameters
+You can initialize the DynamoDB provider pointing to [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) using `endpoint_url` parameter:
- dynamodb_provider = parameters.DynamoDBProvider(table_name="my-table", endpoint_url="http://localhost:8000")
- ```
+=== "builtin_provider_dynamodb_custom_endpoint.py"
+ ```python hl_lines="5 8 15"
+ --8<-- "examples/parameters/src/builtin_provider_dynamodb_custom_endpoint.py"
+ ```
**DynamoDB table structure for multiple values parameters**
@@ -289,39 +239,22 @@ You can retrieve multiple parameters sharing the same `id` by having a sort key
DynamoDB table with `id` primary key, `sk` as sort key` and `value` as attribute
- | id | sk | value |
- | ----------- | ------- | ---------- |
- | my-hash-key | param-a | my-value-a |
- | my-hash-key | param-b | my-value-b |
- | my-hash-key | param-c | my-value-c |
+ | id | sk | value |
+ | ------ | ----------------- | ------------------------------------------------ |
+ | config | endpoint_comments | |
+ | config | limit | 10 |
-With this table, `dynamodb_provider.get_multiple("my-hash-key")` will return a dictionary response in the shape of `sk:value`.
+With this table, `dynamodb_provider.get_multiple("config")` will return a dictionary response in the shape of `sk:value`.
-=== "app.py"
- ```python hl_lines="3 8"
- from aws_lambda_powertools.utilities import parameters
-
- dynamodb_provider = parameters.DynamoDBProvider(table_name="my-table")
-
- def handler(event, context):
- # Retrieve multiple values by performing a Query on the DynamoDB table
- # This returns a dict with the sort key attribute as dict key.
- parameters = dynamodb_provider.get_multiple("my-hash-key")
- for k, v in parameters.items():
- # k: param-a
- # v: "my-value-a"
- print(f"{k}: {v}")
- ```
-
-=== "parameters dict response"
-
- ```json
- {
- "param-a": "my-value-a",
- "param-b": "my-value-b",
- "param-c": "my-value-c"
- }
- ```
+=== "builtin_provider_dynamodb_recursive_parameter.py"
+ ```python hl_lines="5 8 15"
+ --8<-- "examples/parameters/src/builtin_provider_dynamodb_recursive_parameter.py"
+ ```
+
+=== "sam_dynamodb_table_recursive.yaml"
+ ```yaml hl_lines="15-18"
+ --8<-- "examples/parameters/sam/sam_dynamodb_table_recursive.yaml"
+ ```
**Customizing DynamoDBProvider**
@@ -334,33 +267,22 @@ DynamoDB provider can be customized at initialization to match your table struct
| **sort_attr** | No | `sk` | Range key for the DynamoDB table. You don't need to set this if you don't use the `get_multiple()` method. |
| **value_attr** | No | `value` | Name of the attribute containing the parameter value. |
-```python hl_lines="3-8" title="Customizing DynamoDBProvider to suit your table design"
-from aws_lambda_powertools.utilities import parameters
-
-dynamodb_provider = parameters.DynamoDBProvider(
- table_name="my-table",
- key_attr="MyKeyAttr",
- sort_attr="MySortAttr",
- value_attr="MyvalueAttr"
-)
+=== "builtin_provider_dynamodb_custom_fields.py"
+ ```python hl_lines="3 8-10 17"
+ --8<-- "examples/parameters/src/builtin_provider_dynamodb_custom_fields.py"
+ ```
-def handler(event, context):
- value = dynamodb_provider.get("my-parameter")
-```
+=== "sam_dynamodb_custom_fields.yaml"
+ ```yaml hl_lines="5 8-10 17"
+ --8<-- "examples/parameters/sam/sam_dynamodb_custom_fields.yaml"
+ ```
#### AppConfigProvider
-```python hl_lines="5 9" title="Using AppConfigProvider"
-from aws_lambda_powertools.utilities import parameters
-from botocore.config import Config
-
-config = Config(region_name="us-west-1")
-appconf_provider = parameters.AppConfigProvider(environment="my_env", application="my_app", config=config)
-
-def handler(event, context):
- # Retrieve a single secret
- value: bytes = appconf_provider.get("my_conf")
-```
+=== "builtin_provider_appconfig.py"
+ ```python hl_lines="6 9 10 16"
+ --8<-- "examples/parameters/src/builtin_provider_appconfig.py"
+ ```
### Create your own provider
@@ -368,60 +290,27 @@ You can create your own custom parameter store provider by inheriting the `BaseP
All transformation and caching logic is handled by the `get()` and `get_multiple()` methods from the base provider class.
-Here is an example implementation using S3 as a custom parameter store:
-
-```python hl_lines="3 6 17 27" title="Creating a S3 Provider to fetch parameters"
-import copy
-
-from aws_lambda_powertools.utilities import BaseProvider
-import boto3
-
-class S3Provider(BaseProvider):
- bucket_name = None
- client = None
-
- def __init__(self, bucket_name: str):
- # Initialize the client to your custom parameter store
- # E.g.:
-
- self.bucket_name = bucket_name
- self.client = boto3.client("s3")
-
- def _get(self, name: str, **sdk_options) -> str:
- # Retrieve a single value
- # E.g.:
-
- sdk_options["Bucket"] = self.bucket_name
- sdk_options["Key"] = name
-
- response = self.client.get_object(**sdk_options)
- return
-
- def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]:
- # Retrieve multiple values
- # E.g.:
+Here are two examples of implementing a custom parameter store. One using an external service like [Hashicorp Vault](https://www.vaultproject.io/), a widely popular key-value and secret storage and the other one using [Amazon S3](https://aws.amazon.com/s3/?nc1=h_ls), a popular object storage.
- list_sdk_options = copy.deepcopy(sdk_options)
-
- list_sdk_options["Bucket"] = self.bucket_name
- list_sdk_options["Prefix"] = path
-
- list_response = self.client.list_objects_v2(**list_sdk_options)
-
- parameters = {}
-
- for obj in list_response.get("Contents", []):
- get_sdk_options = copy.deepcopy(sdk_options)
-
- get_sdk_options["Bucket"] = self.bucket_name
- get_sdk_options["Key"] = obj["Key"]
+=== "working_with_own_provider_vault.py"
+ ```python hl_lines="5 13 20 24"
+ --8<-- "examples/parameters/src/working_with_own_provider_vault.py"
+ ```
- get_response = self.client.get_object(**get_sdk_options)
+=== "custom_provider_vault.py"
+ ```python hl_lines="6 9 17 24"
+ --8<-- "examples/parameters/src/custom_provider_vault.py"
+ ```
- parameters[obj["Key"]] = get_response["Body"].read().decode()
+=== "working_with_own_provider_s3.py"
+ ```python hl_lines="4 11 18 21"
+ --8<-- "examples/parameters/src/working_with_own_provider_s3.py"
+ ```
- return parameters
-```
+=== "custom_provider_s3.py"
+ ```python hl_lines="6 9 19 29"
+ --8<-- "examples/parameters/src/custom_provider_s3.py"
+ ```
### Deserializing values with transform parameter
@@ -430,28 +319,14 @@ For parameters stored in JSON or Base64 format, you can use the `transform` argu
???+ info
The `transform` argument is available across all providers, including the high level functions.
-=== "High level functions"
-
- ```python hl_lines="4"
- from aws_lambda_powertools.utilities import parameters
-
- def handler(event, context):
- value_from_json = parameters.get_parameter("/my/json/parameter", transform="json")
+=== "working_with_transform_high_level.py"
+ ```python hl_lines="5 12"
+ --8<-- "examples/parameters/src/working_with_transform_high_level.py"
```
-=== "Providers"
-
- ```python hl_lines="7 10"
- from aws_lambda_powertools.utilities import parameters
-
- ssm_provider = parameters.SSMProvider()
-
- def handler(event, context):
- # Transform a JSON string
- value_from_json = ssm_provider.get("/my/json/parameter", transform="json")
-
- # Transform a Base64 encoded string
- value_from_binary = ssm_provider.get("/my/binary/parameter", transform="binary")
+=== "working_with_transform_provider.py"
+ ```python hl_lines="6 9 16"
+ --8<-- "examples/parameters/src/working_with_transform_provider.py"
```
#### Partial transform failures with `get_multiple()`
@@ -462,26 +337,10 @@ You can override this by setting the `raise_on_transform_error` argument to `Tru
For example, if you have three parameters, */param/a*, */param/b* and */param/c*, but */param/c* is malformed:
-```python hl_lines="9 16" title="Raising TransformParameterError at first malformed parameter"
-from aws_lambda_powertools.utilities import parameters
-
-ssm_provider = parameters.SSMProvider()
-
-def handler(event, context):
- # This will display:
- # /param/a: [some value]
- # /param/b: [some value]
- # /param/c: None
- values = ssm_provider.get_multiple("/param", transform="json")
- for k, v in values.items():
- print(f"{k}: {v}")
-
- try:
- # This will raise a TransformParameterError exception
- values = ssm_provider.get_multiple("/param", transform="json", raise_on_transform_error=True)
- except parameters.exceptions.TransformParameterError:
- ...
-```
+=== "handling_error_transform.py"
+ ```python hl_lines="3 14 20"
+ --8<-- "examples/parameters/src/handling_error_transform.py"
+ ```
#### Auto-transform values on suffix
@@ -492,14 +351,10 @@ You can do this with a single request by using `transform="auto"`. This will ins
???+ info
`transform="auto"` feature is available across all providers, including the high level functions.
-```python hl_lines="6" title="Deserializing parameter values based on their suffix"
-from aws_lambda_powertools.utilities import parameters
-
-ssm_provider = parameters.SSMProvider()
-
-def handler(event, context):
- values = ssm_provider.get_multiple("/param", transform="auto")
-```
+=== "working_with_auto_transform.py"
+ ```python hl_lines="1 4 8"
+ --8<-- "examples/parameters/src/working_with_auto_transform.py"
+ ```
For example, if you have two parameters with the following suffixes `.json` and `.binary`:
@@ -521,63 +376,42 @@ The return of `ssm_provider.get_multiple("/param", transform="auto")` call will
You can use arbitrary keyword arguments to pass it directly to the underlying SDK method.
-```python hl_lines="8" title=""
-from aws_lambda_powertools.utilities import parameters
-
-secrets_provider = parameters.SecretsProvider()
-
-def handler(event, context):
- # The 'VersionId' argument will be passed to the underlying get_secret_value() call.
- value = secrets_provider.get("my-secret", VersionId="e62ec170-6b01-48c7-94f3-d7497851a8d2")
-```
+=== "working_with_sdk_additional_arguments.py"
+ ```python hl_lines="1 4 9"
+ --8<-- "examples/parameters/src/working_with_sdk_additional_arguments.py"
+ ```
Here is the mapping between this utility's functions and methods and the underlying SDK:
-| Provider | Function/Method | Client name | Function name |
-| ------------------- | ------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) |
-| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) |
-| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) |
-| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) |
-| Secrets Manager | `get_secret` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) |
-| Secrets Manager | `SecretsManager.get` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) |
-| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) |
-| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) |
-| App Config | `get_app_config` | `appconfig` | [get_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfig.html#AppConfig.Client.get_configuration) |
+| Provider | Function/Method | Client name | Function name |
+| ------------------- | ------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) |
+| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) |
+| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) |
+| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) |
+| Secrets Manager | `get_secret` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) |
+| Secrets Manager | `SecretsManager.get` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) |
+| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) |
+| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) |
+| App Config | `get_app_config` | `appconfigdata` | [start_configuration_session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.start_configuration_session) and [get_latest_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfigdata.html#AppConfigData.Client.get_latest_configuration) |
### Bring your own boto client
You can use `boto3_client` parameter via any of the available [Provider Classes](#built-in-provider-class). Some providers expect a low level boto3 client while others expect a high level boto3 client, here is the mapping for each of them:
-| Provider | Type | Boto client construction |
-| --------------------------------------- | ---------- | ---------------------------- |
-| [SSMProvider](#ssmprovider) | low level | `boto3.client("ssm")` |
-| [SecretsProvider](#secretsprovider) | low level | `boto3.client("secrets")` |
-| [AppConfigProvider](#appconfigprovider) | low level | `boto3.client("appconfig")` |
-| [DynamoDBProvider](#dynamodbprovider) | high level | `boto3.resource("dynamodb")` |
+| Provider | Type | Boto client construction |
+| --------------------------------------- | ---------- | ------------------------------- |
+| [SSMProvider](#ssmprovider) | low level | `boto3.client("ssm")` |
+| [SecretsProvider](#secretsprovider) | low level | `boto3.client("secrets")` |
+| [AppConfigProvider](#appconfigprovider) | low level | `boto3.client("appconfigdata")` |
+| [DynamoDBProvider](#dynamodbprovider) | high level | `boto3.resource("dynamodb")` |
Bringing them together in a single code snippet would look like this:
-```python title="Example: passing a custom boto3 client for each provider"
-import boto3
-from botocore.config import Config
-
-from aws_lambda_powertools.utilities import parameters
-
-config = Config(region_name="us-west-1")
-
-# construct boto clients with any custom configuration
-ssm = boto3.client("ssm", config=config)
-secrets = boto3.client("secrets", config=config)
-appconfig = boto3.client("appconfig", config=config)
-dynamodb = boto3.resource("dynamodb", config=config)
-
-ssm_provider = parameters.SSMProvider(boto3_client=ssm)
-secrets_provider = parameters.SecretsProvider(boto3_client=secrets)
-appconf_provider = parameters.AppConfigProvider(boto3_client=appconfig, environment="my_env", application="my_app")
-dynamodb_provider = parameters.DynamoDBProvider(boto3_client=dynamodb, table_name="my-table")
-
-```
+=== "custom_boto3_all_providers.py"
+ ```python hl_lines="4 6"
+ --8<-- "examples/parameters/src/custom_boto3_all_providers.py"
+ ```
???+ question "When is this useful?"
Injecting a custom boto3 client can make unit/snapshot testing easier, including SDK customizations.
@@ -591,49 +425,20 @@ The **`config`** , **`boto3_session`**, and **`boto3_client`** parameters enabl
When using VPC private endpoints, you can pass a custom client altogether. It's also useful for testing when injecting fake instances.
-=== "Custom session"
-
- ```python hl_lines="2 4 5"
- from aws_lambda_powertools.utilities import parameters
- import boto3
-
- boto3_session = boto3.session.Session()
- ssm_provider = parameters.SSMProvider(boto3_session=boto3_session)
-
- def handler(event, context):
- # Retrieve a single parameter
- value = ssm_provider.get("/my/parameter")
- ...
- ```
-=== "Custom config"
-
- ```python hl_lines="2 4 5"
- from aws_lambda_powertools.utilities import parameters
- from botocore.config import Config
-
- boto_config = Config()
- ssm_provider = parameters.SSMProvider(config=boto_config)
-
- def handler(event, context):
- # Retrieve a single parameter
- value = ssm_provider.get("/my/parameter")
- ...
- ```
-
-=== "Custom client"
-
- ```python hl_lines="2 4 5"
- from aws_lambda_powertools.utilities import parameters
- import boto3
+=== "custom_boto_session.py"
+ ```python hl_lines="5 6"
+ --8<-- "examples/parameters/src/custom_boto_session.py"
+ ```
- boto3_client= boto3.client("ssm")
- ssm_provider = parameters.SSMProvider(boto3_client=boto3_client)
+=== "custom_boto_config.py"
+ ```python hl_lines="5 6"
+ --8<-- "examples/parameters/src/custom_boto_config.py"
+ ```
- def handler(event, context):
- # Retrieve a single parameter
- value = ssm_provider.get("/my/parameter")
- ...
- ```
+=== "custom_boto_client.py"
+ ```python hl_lines="5 6"
+ --8<-- "examples/parameters/src/custom_boto_client.py"
+ ```
## Testing your code
@@ -641,72 +446,32 @@ The **`config`** , **`boto3_session`**, and **`boto3_client`** parameters enabl
For unit testing your applications, you can mock the calls to the parameters utility to avoid calling AWS APIs. This can be achieved in a number of ways - in this example, we use the [pytest monkeypatch fixture](https://docs.pytest.org/en/latest/how-to/monkeypatch.html) to patch the `parameters.get_parameter` method:
-=== "tests.py"
- ```python
- from src import index
-
- def test_handler(monkeypatch):
-
- def mockreturn(name):
- return "mock_value"
-
- monkeypatch.setattr(index.parameters, "get_parameter", mockreturn)
- return_val = index.handler({}, {})
- assert return_val.get('message') == 'mock_value'
- ```
-
-=== "src/index.py"
- ```python
- from aws_lambda_powertools.utilities import parameters
+=== "test_single_mock.py"
+ ```python hl_lines="4 8"
+ --8<-- "examples/parameters/tests/test_single_mock.py"
+ ```
- def handler(event, context):
- # Retrieve a single parameter
- value = parameters.get_parameter("my-parameter-name")
- return {"message": value}
- ```
+=== "single_mock.py"
+ ```python
+ --8<-- "examples/parameters/tests/src/single_mock.py"
+ ```
If we need to use this pattern across multiple tests, we can avoid repetition by refactoring to use our own pytest fixture:
-=== "tests.py"
- ```python
- import pytest
-
- from src import index
-
- @pytest.fixture
- def mock_parameter_response(monkeypatch):
- def mockreturn(name):
- return "mock_value"
-
- monkeypatch.setattr(index.parameters, "get_parameter", mockreturn)
-
- # Pass our fixture as an argument to all tests where we want to mock the get_parameter response
- def test_handler(mock_parameter_response):
- return_val = index.handler({}, {})
- assert return_val.get('message') == 'mock_value'
-
- ```
+=== "test_with_fixture.py"
+ ```python hl_lines="5 10"
+ --8<-- "examples/parameters/tests/test_with_fixture.py"
+ ```
Alternatively, if we need more fully featured mocking (for example checking the arguments passed to `get_parameter`), we
can use [unittest.mock](https://docs.python.org/3/library/unittest.mock.html) from the python stdlib instead of pytest's `monkeypatch` fixture. In this example, we use the
[patch](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch) decorator to replace the `aws_lambda_powertools.utilities.parameters.get_parameter` function with a [MagicMock](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock)
object named `get_parameter_mock`.
-=== "tests.py"
- ```python
- from unittest.mock import patch
- from src import index
-
- # Replaces "aws_lambda_powertools.utilities.parameters.get_parameter" with a Mock object
- @patch("aws_lambda_powertools.utilities.parameters.get_parameter")
- def test_handler(get_parameter_mock):
- get_parameter_mock.return_value = 'mock_value'
-
- return_val = index.handler({}, {})
- get_parameter_mock.assert_called_with("my-parameter-name")
- assert return_val.get('message') == 'mock_value'
-
- ```
+=== "test_with_monkeypatch.py"
+ ```python hl_lines="7 12"
+ --8<-- "examples/parameters/tests/test_with_monkeypatch.py"
+ ```
### Clearing cache
@@ -714,66 +479,17 @@ Parameters utility caches all parameter values for performance and cost reasons.
Within your tests, you can use `clear_cache` method available in [every provider](#built-in-provider-class). When using multiple providers or higher level functions like `get_parameter`, use `clear_caches` standalone function to clear cache globally.
-=== "clear_cache method"
- ```python hl_lines="9"
- import pytest
-
- from src import app
-
-
- @pytest.fixture(scope="function", autouse=True)
- def clear_parameters_cache():
- yield
- app.ssm_provider.clear_cache() # This will clear SSMProvider cache
-
- @pytest.fixture
- def mock_parameter_response(monkeypatch):
- def mockreturn(name):
- return "mock_value"
-
- monkeypatch.setattr(app.ssm_provider, "get", mockreturn)
-
- # Pass our fixture as an argument to all tests where we want to mock the get_parameter response
- def test_handler(mock_parameter_response):
- return_val = app.handler({}, {})
- assert return_val.get('message') == 'mock_value'
- ```
-
-=== "global clear_caches"
- ```python hl_lines="10"
- import pytest
-
- from aws_lambda_powertools.utilities import parameters
- from src import app
-
-
- @pytest.fixture(scope="function", autouse=True)
- def clear_parameters_cache():
- yield
- parameters.clear_caches() # This will clear all providers cache
-
- @pytest.fixture
- def mock_parameter_response(monkeypatch):
- def mockreturn(name):
- return "mock_value"
-
- monkeypatch.setattr(app.ssm_provider, "get", mockreturn)
+=== "test_clear_cache_method.py"
+ ```python hl_lines="8"
+ --8<-- "examples/parameters/tests/test_clear_cache_method.py"
+ ```
- # Pass our fixture as an argument to all tests where we want to mock the get_parameter response
- def test_handler(mock_parameter_response):
- return_val = app.handler({}, {})
- assert return_val.get('message') == 'mock_value'
- ```
+=== "test_clear_cache_global.py"
+ ```python hl_lines="10"
+ --8<-- "examples/parameters/tests/test_clear_cache_global.py"
+ ```
=== "app.py"
- ```python
- from aws_lambda_powertools.utilities import parameters
- from botocore.config import Config
-
- ssm_provider = parameters.SSMProvider(config=Config(region_name="us-west-1"))
-
-
- def handler(event, context):
- value = ssm_provider.get("/my/parameter")
- return {"message": value}
- ```
+ ```python
+ --8<-- "examples/parameters/tests/src/app.py"
+ ```
diff --git a/examples/parameters/sam/sam_dynamodb_custom_fields.yaml b/examples/parameters/sam/sam_dynamodb_custom_fields.yaml
new file mode 100644
index 00000000000..1c864a0e747
--- /dev/null
+++ b/examples/parameters/sam/sam_dynamodb_custom_fields.yaml
@@ -0,0 +1,22 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: 'DynamoDB Table example'
+Resources:
+ ParameterTable:
+ Type: AWS::DynamoDB::Table
+ Properties:
+ TableName: ParameterTable
+ AttributeDefinitions:
+ - AttributeName: IdKeyAttr
+ AttributeType: S
+ - AttributeName: SkKeyAttr
+ AttributeType: S
+ KeySchema:
+ - AttributeName: IdKeyAttr
+ KeyType: HASH
+ - AttributeName: SkKeyAttr
+ KeyType: RANGE
+ TimeToLiveSpecification:
+ AttributeName: expiration
+ Enabled: true
+ BillingMode: PAY_PER_REQUEST
diff --git a/examples/parameters/sam/sam_dynamodb_table_recursive.yaml b/examples/parameters/sam/sam_dynamodb_table_recursive.yaml
new file mode 100644
index 00000000000..6e02c2f8f6d
--- /dev/null
+++ b/examples/parameters/sam/sam_dynamodb_table_recursive.yaml
@@ -0,0 +1,22 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: 'DynamoDB Table example'
+Resources:
+ ParameterTable:
+ Type: AWS::DynamoDB::Table
+ Properties:
+ TableName: ParameterTable
+ AttributeDefinitions:
+ - AttributeName: id
+ AttributeType: S
+ - AttributeName: sk
+ AttributeType: S
+ KeySchema:
+ - AttributeName: id
+ KeyType: HASH
+ - AttributeName: sk
+ KeyType: RANGE
+ TimeToLiveSpecification:
+ AttributeName: expiration
+ Enabled: true
+ BillingMode: PAY_PER_REQUEST
diff --git a/examples/parameters/sam/sam_dynamodb_table_single.yaml b/examples/parameters/sam/sam_dynamodb_table_single.yaml
new file mode 100644
index 00000000000..17d25553fa7
--- /dev/null
+++ b/examples/parameters/sam/sam_dynamodb_table_single.yaml
@@ -0,0 +1,18 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: 'DynamoDB Table example'
+Resources:
+ ParameterTable:
+ Type: AWS::DynamoDB::Table
+ Properties:
+ TableName: ParameterTable
+ AttributeDefinitions:
+ - AttributeName: id
+ AttributeType: S
+ KeySchema:
+ - AttributeName: id
+ KeyType: HASH
+ TimeToLiveSpecification:
+ AttributeName: expiration
+ Enabled: true
+ BillingMode: PAY_PER_REQUEST
diff --git a/examples/parameters/src/appconfig_force_fetch.py b/examples/parameters/src/appconfig_force_fetch.py
new file mode 100644
index 00000000000..3cf5cbda6fd
--- /dev/null
+++ b/examples/parameters/src/appconfig_force_fetch.py
@@ -0,0 +1,21 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = parameters.get_app_config(
+ name="config", environment="dev", application="comments", force_fetch=True
+ )
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/appconfig_with_cache.py b/examples/parameters/src/appconfig_with_cache.py
new file mode 100644
index 00000000000..55514e12ea7
--- /dev/null
+++ b/examples/parameters/src/appconfig_with_cache.py
@@ -0,0 +1,21 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = parameters.get_app_config(
+ name="config", environment="dev", application="comments", max_age=20
+ )
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_appconfig.py b/examples/parameters/src/builtin_provider_appconfig.py
new file mode 100644
index 00000000000..cf734e29af8
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_appconfig.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+import requests
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+config = Config(region_name="sa-east-1")
+appconf_provider = parameters.AppConfigProvider(environment="dev", application="comments", config=config)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = appconf_provider.get("config")
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_dynamodb_custom_endpoint.py b/examples/parameters/src/builtin_provider_dynamodb_custom_endpoint.py
new file mode 100644
index 00000000000..e77506f27d7
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_dynamodb_custom_endpoint.py
@@ -0,0 +1,22 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+dynamodb_provider = parameters.DynamoDBProvider(table_name="ParameterTable", endpoint_url="http://localhost:8000")
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in DynamoDB Table
+ endpoint_comments: Any = dynamodb_provider.get("comments_endpoint")
+
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_dynamodb_custom_fields.py b/examples/parameters/src/builtin_provider_dynamodb_custom_fields.py
new file mode 100644
index 00000000000..6936f7f0a19
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_dynamodb_custom_fields.py
@@ -0,0 +1,24 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+dynamodb_provider = parameters.DynamoDBProvider(
+ table_name="ParameterTable", key_attr="IdKeyAttr", sort_attr="SkKeyAttr", value_attr="ValueAttr"
+)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in DynamoDB Table
+ endpoint_comments: Any = dynamodb_provider.get("comments_endpoint")
+
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_dynamodb_recursive_parameter.py b/examples/parameters/src/builtin_provider_dynamodb_recursive_parameter.py
new file mode 100644
index 00000000000..7db0d4d913a
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_dynamodb_recursive_parameter.py
@@ -0,0 +1,33 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+dynamodb_provider = parameters.DynamoDBProvider(table_name="ParameterTable")
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Retrieve multiple parameters using HASH KEY
+ all_parameters: Any = dynamodb_provider.get_multiple("config")
+ endpoint_comments = "https://jsonplaceholder.typicode.com/noexists/"
+ limit = 2
+
+ for parameter, value in all_parameters.items():
+
+ if parameter == "endpoint_comments":
+ endpoint_comments = value
+
+ if parameter == "limit":
+ limit = int(value)
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[limit]}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_dynamodb_single_parameter.py b/examples/parameters/src/builtin_provider_dynamodb_single_parameter.py
new file mode 100644
index 00000000000..036058f2b33
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_dynamodb_single_parameter.py
@@ -0,0 +1,22 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+dynamodb_provider = parameters.DynamoDBProvider(table_name="ParameterTable")
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in DynamoDB Table
+ endpoint_comments: Any = dynamodb_provider.get("comments_endpoint")
+
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_secret.py b/examples/parameters/src/builtin_provider_secret.py
new file mode 100644
index 00000000000..449664c1863
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_secret.py
@@ -0,0 +1,27 @@
+from typing import Any
+
+import requests
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+config = Config(region_name="sa-east-1", connect_timeout=1, retries={"total_max_attempts": 2, "max_attempts": 5})
+ssm_provider = parameters.SecretsProvider(config=config)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in SSM Parameters
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments")
+ # An API-KEY is a sensitive data and should be stored in SecretsManager
+ api_key: Any = ssm_provider.get("/lambda-powertools/api-key")
+
+ headers: dict = {"X-API-Key": api_key}
+
+ comments: requests.Response = requests.get(endpoint_comments, headers=headers)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_ssm_recursive_parameter.py b/examples/parameters/src/builtin_provider_ssm_recursive_parameter.py
new file mode 100644
index 00000000000..ae6c6a29a87
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_ssm_recursive_parameter.py
@@ -0,0 +1,44 @@
+from typing import Any
+
+import boto3
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+# assuming role from another account to get parameter there
+# see: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
+sts_client = boto3.client("sts")
+assumed_role_object = sts_client.assume_role(
+ RoleArn="arn:aws:iam::account-of-role-to-assume:role/name-of-role", RoleSessionName="RoleAssume1"
+)
+credentials = assumed_role_object["Credentials"]
+
+# using temporary credentials in your SSMProvider provider
+# see: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html#module-boto3.session
+boto3_session = boto3.session.Session(
+ region_name="us-east-1",
+ aws_access_key_id=credentials["AccessKeyId"],
+ aws_secret_access_key=credentials["SecretAccessKey"],
+ aws_session_token=credentials["SessionToken"],
+)
+ssm_provider = parameters.SSMProvider(boto3_session=boto3_session)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve multiple parameters from a path prefix
+ all_parameters: Any = ssm_provider.get_multiple("/lambda-powertools/")
+ endpoint_comments = "https://jsonplaceholder.typicode.com/noexists/"
+
+ for parameter, value in all_parameters.items():
+
+ if parameter == "endpoint_comments":
+ endpoint_comments = value
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10]}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_ssm_single_parameter.py b/examples/parameters/src/builtin_provider_ssm_single_parameter.py
new file mode 100644
index 00000000000..28217b4deb2
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_ssm_single_parameter.py
@@ -0,0 +1,25 @@
+from typing import Any
+
+import requests
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+# changing region_name, connect_timeout and retrie configurations
+# see: https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html
+config = Config(region_name="sa-east-1", connect_timeout=1, retries={"total_max_attempts": 2, "max_attempts": 5})
+ssm_provider = parameters.SSMProvider(config=config)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = ssm_provider.get("/lambda-powertools/endpoint_comments")
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/builtin_provider_ssm_with_decrypt.py b/examples/parameters/src/builtin_provider_ssm_with_decrypt.py
new file mode 100644
index 00000000000..1bb4444726a
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_ssm_with_decrypt.py
@@ -0,0 +1,28 @@
+from typing import Any
+from uuid import uuid4
+
+import boto3
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+ec2 = boto3.resource("ec2")
+ssm_provider = parameters.SSMProvider()
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve the key pair from secure string parameter
+ ec2_pem: Any = ssm_provider.get("/lambda-powertools/ec2_pem", decrypt=True)
+
+ name_key_pair = f"kp_{uuid4()}"
+
+ ec2.import_key_pair(KeyName=name_key_pair, PublicKeyMaterial=ec2_pem)
+
+ ec2.create_instances(
+ ImageId="ami-026b57f3c383c2eec", InstanceType="t2.micro", MinCount=1, MaxCount=1, KeyName=name_key_pair
+ )
+
+ return {"message": "EC2 created", "success": True}
+ except parameters.exceptions.GetParameterError as error:
+ return {"message": f"Error creating EC2 => {str(error)}", "success": False}
diff --git a/examples/parameters/src/builtin_provider_ssm_with_no_recursive.py b/examples/parameters/src/builtin_provider_ssm_with_no_recursive.py
new file mode 100644
index 00000000000..0f92d27bfbc
--- /dev/null
+++ b/examples/parameters/src/builtin_provider_ssm_with_no_recursive.py
@@ -0,0 +1,39 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+ssm_provider = parameters.SSMProvider()
+
+
+class ConfigNotFound(Exception):
+ ...
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve multiple parameters from a path prefix
+ # /config = root
+ # /config/endpoint = url
+ # /config/endpoint/query = querystring
+ all_parameters: Any = ssm_provider.get_multiple("/config", recursive=False)
+ endpoint_comments = "https://jsonplaceholder.typicode.com/comments/"
+
+ for parameter, value in all_parameters.items():
+
+ # query parameter is used to query endpoint
+ if "query" in parameter:
+ endpoint_comments = f"{endpoint_comments}{value}"
+ break
+ else:
+ # scheme config was not found because get_multiple is not recursive
+ raise ConfigNotFound("URL query parameter was not found")
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/custom_boto3_all_providers.py b/examples/parameters/src/custom_boto3_all_providers.py
new file mode 100644
index 00000000000..629eba6e5c6
--- /dev/null
+++ b/examples/parameters/src/custom_boto3_all_providers.py
@@ -0,0 +1,17 @@
+import boto3
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+
+config = Config(region_name="us-west-1")
+
+# construct boto clients with any custom configuration
+ssm = boto3.client("ssm", config=config)
+secrets = boto3.client("secrets", config=config)
+appconfig = boto3.client("appconfigdata", config=config)
+dynamodb = boto3.resource("dynamodb", config=config)
+
+ssm_provider = parameters.SSMProvider(boto3_client=ssm)
+secrets_provider = parameters.SecretsProvider(boto3_client=secrets)
+appconf_provider = parameters.AppConfigProvider(boto3_client=appconfig, environment="my_env", application="my_app")
+dynamodb_provider = parameters.DynamoDBProvider(boto3_client=dynamodb, table_name="my-table")
diff --git a/examples/parameters/src/custom_boto_client.py b/examples/parameters/src/custom_boto_client.py
new file mode 100644
index 00000000000..be81bb574a3
--- /dev/null
+++ b/examples/parameters/src/custom_boto_client.py
@@ -0,0 +1,13 @@
+import boto3
+
+from aws_lambda_powertools.utilities import parameters
+
+boto3_client = boto3.client("ssm")
+ssm_provider = parameters.SSMProvider(boto3_client=boto3_client)
+
+
+def handler(event, context):
+ # Retrieve a single parameter
+ value = ssm_provider.get("/my/parameter")
+
+ return value
diff --git a/examples/parameters/src/custom_boto_config.py b/examples/parameters/src/custom_boto_config.py
new file mode 100644
index 00000000000..8401a9bab89
--- /dev/null
+++ b/examples/parameters/src/custom_boto_config.py
@@ -0,0 +1,13 @@
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+
+boto_config = Config()
+ssm_provider = parameters.SSMProvider(config=boto_config)
+
+
+def handler(event, context):
+ # Retrieve a single parameter
+ value = ssm_provider.get("/my/parameter")
+
+ return value
diff --git a/examples/parameters/src/custom_boto_session.py b/examples/parameters/src/custom_boto_session.py
new file mode 100644
index 00000000000..c65481aa305
--- /dev/null
+++ b/examples/parameters/src/custom_boto_session.py
@@ -0,0 +1,13 @@
+import boto3
+
+from aws_lambda_powertools.utilities import parameters
+
+boto3_session = boto3.session.Session()
+ssm_provider = parameters.SSMProvider(boto3_session=boto3_session)
+
+
+def handler(event, context):
+ # Retrieve a single parameter
+ value = ssm_provider.get("/my/parameter")
+
+ return value
diff --git a/examples/parameters/src/custom_provider_s3.py b/examples/parameters/src/custom_provider_s3.py
new file mode 100644
index 00000000000..7233ac0b307
--- /dev/null
+++ b/examples/parameters/src/custom_provider_s3.py
@@ -0,0 +1,52 @@
+import copy
+from typing import Dict
+
+import boto3
+
+from aws_lambda_powertools.utilities.parameters import BaseProvider
+
+
+class S3Provider(BaseProvider):
+ def __init__(self, bucket_name: str):
+ # Initialize the client to your custom parameter store
+ # E.g.:
+
+ super().__init__()
+
+ self.bucket_name = bucket_name
+ self.client = boto3.client("s3")
+
+ def _get(self, name: str, **sdk_options) -> str:
+ # Retrieve a single value
+ # E.g.:
+
+ sdk_options["Bucket"] = self.bucket_name
+ sdk_options["Key"] = name
+
+ response = self.client.get_object(**sdk_options)
+ return response["Body"].read().decode()
+
+ def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]:
+ # Retrieve multiple values
+ # E.g.:
+
+ list_sdk_options = copy.deepcopy(sdk_options)
+
+ list_sdk_options["Bucket"] = self.bucket_name
+ list_sdk_options["Prefix"] = path
+
+ list_response = self.client.list_objects_v2(**list_sdk_options)
+
+ parameters = {}
+
+ for obj in list_response.get("Contents", []):
+ get_sdk_options = copy.deepcopy(sdk_options)
+
+ get_sdk_options["Bucket"] = self.bucket_name
+ get_sdk_options["Key"] = obj["Key"]
+
+ get_response = self.client.get_object(**get_sdk_options)
+
+ parameters[obj["Key"]] = get_response["Body"].read().decode()
+
+ return parameters
diff --git a/examples/parameters/src/custom_provider_vault.py b/examples/parameters/src/custom_provider_vault.py
new file mode 100644
index 00000000000..06d0a929fff
--- /dev/null
+++ b/examples/parameters/src/custom_provider_vault.py
@@ -0,0 +1,36 @@
+import json
+from typing import Dict
+
+from hvac import Client
+
+from aws_lambda_powertools.utilities.parameters import BaseProvider
+
+
+class VaultProvider(BaseProvider):
+ def __init__(self, vault_url: str, vault_token: str) -> None:
+
+ super().__init__()
+
+ self.vault_client = Client(url=vault_url, verify=False, timeout=10)
+ self.vault_client.token = vault_token
+
+ def _get(self, name: str, **sdk_options) -> str:
+
+ # for example proposal, the mountpoint is always /secret
+ kv_configuration = self.vault_client.secrets.kv.v2.read_secret(path=name)
+
+ return json.dumps(kv_configuration["data"]["data"])
+
+ def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]:
+
+ list_secrets = {}
+ all_secrets = self.vault_client.secrets.kv.v2.list_secrets(path=path)
+
+ # for example proposal, the mountpoint is always /secret
+ for secret in all_secrets["data"]["keys"]:
+ kv_configuration = self.vault_client.secrets.kv.v2.read_secret(path=secret)
+
+ for key, value in kv_configuration["data"]["data"].items():
+ list_secrets[key] = value
+
+ return list_secrets
diff --git a/examples/parameters/src/get_parameter_by_name_error_handling.py b/examples/parameters/src/get_parameter_by_name_error_handling.py
new file mode 100644
index 00000000000..7cae4525e83
--- /dev/null
+++ b/examples/parameters/src/get_parameter_by_name_error_handling.py
@@ -0,0 +1,21 @@
+from typing import Any
+
+from aws_lambda_powertools.utilities.parameters.ssm import get_parameters_by_name
+
+parameters = {
+ "/develop/service/commons/telemetry/config": {"max_age": 300, "transform": "json"},
+ # it would fail by default
+ "/this/param/does/not/exist": {},
+}
+
+
+def handler(event, context):
+ values: dict[str, Any] = get_parameters_by_name(parameters=parameters, raise_on_error=False)
+ errors: list[str] = values.get("_errors", [])
+
+ # Handle gracefully, since '/this/param/does/not/exist' will only be available in `_errors`
+ if errors:
+ ...
+
+ for parameter, value in values.items():
+ print(f"{parameter}: {value}")
diff --git a/examples/parameters/src/getting_started_appconfig.py b/examples/parameters/src/getting_started_appconfig.py
new file mode 100644
index 00000000000..fdb0c91d631
--- /dev/null
+++ b/examples/parameters/src/getting_started_appconfig.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = parameters.get_app_config(name="config", environment="dev", application="comments")
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/getting_started_parameter_by_name.py b/examples/parameters/src/getting_started_parameter_by_name.py
new file mode 100644
index 00000000000..95d63937ab7
--- /dev/null
+++ b/examples/parameters/src/getting_started_parameter_by_name.py
@@ -0,0 +1,17 @@
+from typing import Any
+
+from aws_lambda_powertools.utilities.parameters.ssm import get_parameters_by_name
+
+parameters = {
+ "/develop/service/commons/telemetry/config": {"max_age": 300, "transform": "json"},
+ "/no_cache_param": {"max_age": 0},
+ # inherit default values
+ "/develop/service/payment/api/capture/url": {},
+}
+
+
+def handler(event, context):
+ # This returns a dict with the parameter name as key
+ response: dict[str, Any] = get_parameters_by_name(parameters=parameters, max_age=60)
+ for parameter, value in response.items():
+ print(f"{parameter}: {value}")
diff --git a/examples/parameters/src/getting_started_recursive_ssm_parameter.py b/examples/parameters/src/getting_started_recursive_ssm_parameter.py
new file mode 100644
index 00000000000..5325a7fba96
--- /dev/null
+++ b/examples/parameters/src/getting_started_recursive_ssm_parameter.py
@@ -0,0 +1,26 @@
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve multiple parameters from a path prefix
+ all_parameters: dict = parameters.get_parameters("/lambda-powertools/", max_age=20)
+ endpoint_comments = None
+
+ for parameter, value in all_parameters.items():
+
+ if parameter == "endpoint_comments":
+ endpoint_comments = value
+
+ if endpoint_comments is None:
+ return {"comments": None}
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10]}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/getting_started_secret.py b/examples/parameters/src/getting_started_secret.py
new file mode 100644
index 00000000000..1f10394e834
--- /dev/null
+++ b/examples/parameters/src/getting_started_secret.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in SSM Parameters
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments")
+ # An API-KEY is a sensitive data and should be stored in SecretsManager
+ api_key: Any = parameters.get_secret("/lambda-powertools/api-key")
+
+ headers: dict = {"X-API-Key": api_key}
+
+ comments: requests.Response = requests.get(endpoint_comments, headers=headers)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/getting_started_single_ssm_parameter.py b/examples/parameters/src/getting_started_single_ssm_parameter.py
new file mode 100644
index 00000000000..d31c7a180f1
--- /dev/null
+++ b/examples/parameters/src/getting_started_single_ssm_parameter.py
@@ -0,0 +1,17 @@
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext) -> dict:
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: str = parameters.get_parameter("/lambda-powertools/endpoint_comments") # type: ignore[assignment] # noqa: E501
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/handling_error_transform.py b/examples/parameters/src/handling_error_transform.py
new file mode 100644
index 00000000000..e81a9e81809
--- /dev/null
+++ b/examples/parameters/src/handling_error_transform.py
@@ -0,0 +1,22 @@
+from typing import Any
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+ssm_provider = parameters.SSMProvider()
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ # This will display:
+ # /param/a: [some value]
+ # /param/b: [some value]
+ # /param/c: None
+ values: Any = ssm_provider.get_multiple("/param", transform="json")
+ for key, value in values.items():
+ print(f"{key}: {value}")
+
+ try:
+ # This will raise a TransformParameterError exception
+ values = ssm_provider.get_multiple("/param", transform="json", raise_on_transform_error=True)
+ except parameters.exceptions.TransformParameterError:
+ ...
diff --git a/examples/parameters/src/recursive_ssm_parameter_force_fetch.py b/examples/parameters/src/recursive_ssm_parameter_force_fetch.py
new file mode 100644
index 00000000000..6082a0173d4
--- /dev/null
+++ b/examples/parameters/src/recursive_ssm_parameter_force_fetch.py
@@ -0,0 +1,25 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve multiple parameters from a path prefix
+ all_parameters: Any = parameters.get_parameters("/lambda-powertools/", force_fetch=True)
+ endpoint_comments = "https://jsonplaceholder.typicode.com/noexists/"
+
+ for parameter, value in all_parameters.items():
+
+ if parameter == "endpoint_comments":
+ endpoint_comments = value
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10]}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/recursive_ssm_parameter_with_cache.py b/examples/parameters/src/recursive_ssm_parameter_with_cache.py
new file mode 100644
index 00000000000..9cf48b39dde
--- /dev/null
+++ b/examples/parameters/src/recursive_ssm_parameter_with_cache.py
@@ -0,0 +1,25 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve multiple parameters from a path prefix
+ all_parameters: Any = parameters.get_parameters("/lambda-powertools/", max_age=20)
+ endpoint_comments = "https://jsonplaceholder.typicode.com/noexists/"
+
+ for parameter, value in all_parameters.items():
+
+ if parameter == "endpoint_comments":
+ endpoint_comments = value
+
+ # the value of parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10]}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/secret_force_fetch.py b/examples/parameters/src/secret_force_fetch.py
new file mode 100644
index 00000000000..121d9f57bfb
--- /dev/null
+++ b/examples/parameters/src/secret_force_fetch.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in SSM Parameters
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments")
+ # An API-KEY is a sensitive data and should be stored in SecretsManager
+ api_key: Any = parameters.get_secret("/lambda-powertools/api-key", force_fetch=True)
+
+ headers: dict = {"X-API-Key": api_key}
+
+ comments: requests.Response = requests.get(endpoint_comments, headers=headers)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/secret_with_cache.py b/examples/parameters/src/secret_with_cache.py
new file mode 100644
index 00000000000..8d3ed927107
--- /dev/null
+++ b/examples/parameters/src/secret_with_cache.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Usually an endpoint is not sensitive data, so we store it in SSM Parameters
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments")
+ # An API-KEY is a sensitive data and should be stored in SecretsManager
+ api_key: Any = parameters.get_secret("/lambda-powertools/api-key", max_age=20)
+
+ headers: dict = {"X-API-Key": api_key}
+
+ comments: requests.Response = requests.get(endpoint_comments, headers=headers)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/single_ssm_parameter_force_fetch.py b/examples/parameters/src/single_ssm_parameter_force_fetch.py
new file mode 100644
index 00000000000..7b45c1be216
--- /dev/null
+++ b/examples/parameters/src/single_ssm_parameter_force_fetch.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter with 20s cache
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments", force_fetch=True)
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/single_ssm_parameter_with_cache.py b/examples/parameters/src/single_ssm_parameter_with_cache.py
new file mode 100644
index 00000000000..1be8632bc00
--- /dev/null
+++ b/examples/parameters/src/single_ssm_parameter_with_cache.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter with 20s cache
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments", max_age=20)
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/working_with_auto_transform.py b/examples/parameters/src/working_with_auto_transform.py
new file mode 100644
index 00000000000..fc29d376606
--- /dev/null
+++ b/examples/parameters/src/working_with_auto_transform.py
@@ -0,0 +1,10 @@
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+ssm_provider = parameters.SSMProvider()
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ values = ssm_provider.get_multiple("/param", transform="auto")
+
+ return values
diff --git a/examples/parameters/src/working_with_own_provider_s3.py b/examples/parameters/src/working_with_own_provider_s3.py
new file mode 100644
index 00000000000..d4f011a9e23
--- /dev/null
+++ b/examples/parameters/src/working_with_own_provider_s3.py
@@ -0,0 +1,30 @@
+from typing import Any
+
+import requests
+from custom_provider_s3 import S3Provider
+
+from aws_lambda_powertools import Logger
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+logger = Logger()
+
+s3_provider = S3Provider(bucket_name="bucket_name")
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Retrieve a single parameter using key
+ endpoint_comments: Any = s3_provider.get("comments_endpoint")
+ # you can get all parameters using get_multiple and specifying a bucket prefix
+ # # for testing purposes we will not use it
+ all_parameters: Any = s3_provider.get_multiple("/")
+ logger.info(all_parameters)
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/working_with_own_provider_vault.py b/examples/parameters/src/working_with_own_provider_vault.py
new file mode 100644
index 00000000000..7be9ea60242
--- /dev/null
+++ b/examples/parameters/src/working_with_own_provider_vault.py
@@ -0,0 +1,35 @@
+from typing import Any
+
+import hvac
+import requests
+from custom_provider_vault import VaultProvider
+
+from aws_lambda_powertools import Logger
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+logger = Logger()
+
+# In production you must use Vault over HTTPS and certificates.
+vault_provider = VaultProvider(vault_url="http://192.168.68.105:8200/", vault_token="YOUR_TOKEN")
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = vault_provider.get("comments_endpoint", transform="json")
+
+ # you can get all parameters using get_multiple and specifying vault mount point
+ # # for testing purposes we will not use it
+ all_parameters: Any = vault_provider.get_multiple("/")
+ logger.info(all_parameters)
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments["url"])
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except hvac.exceptions.InvalidPath as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
+ # general exception
+ except Exception as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/working_with_sdk_additional_arguments.py b/examples/parameters/src/working_with_sdk_additional_arguments.py
new file mode 100644
index 00000000000..4f99714d817
--- /dev/null
+++ b/examples/parameters/src/working_with_sdk_additional_arguments.py
@@ -0,0 +1,11 @@
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+secrets_provider = parameters.SecretsProvider()
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ # The 'VersionId' argument will be passed to the underlying get_secret_value() call.
+ value = secrets_provider.get("my-secret", VersionId="e62ec170-6b01-48c7-94f3-d7497851a8d2")
+
+ return value
diff --git a/examples/parameters/src/working_with_transform_high_level.py b/examples/parameters/src/working_with_transform_high_level.py
new file mode 100644
index 00000000000..ee00862bf72
--- /dev/null
+++ b/examples/parameters/src/working_with_transform_high_level.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+import requests
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+
+def lambda_handler(event: dict, context: LambdaContext) -> dict:
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = parameters.get_parameter("/lambda-powertools/endpoint_comments", transform="json")
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/src/working_with_transform_provider.py b/examples/parameters/src/working_with_transform_provider.py
new file mode 100644
index 00000000000..948ae1710b3
--- /dev/null
+++ b/examples/parameters/src/working_with_transform_provider.py
@@ -0,0 +1,23 @@
+from typing import Any
+
+import requests
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+from aws_lambda_powertools.utilities.typing import LambdaContext
+
+config = Config(region_name="sa-east-1")
+appconf_provider = parameters.AppConfigProvider(environment="dev", application="comments", config=config)
+
+
+def lambda_handler(event: dict, context: LambdaContext):
+ try:
+ # Retrieve a single parameter
+ endpoint_comments: Any = appconf_provider.get("config", transform="json")
+
+ # the value of this parameter is https://jsonplaceholder.typicode.com/comments/
+ comments: requests.Response = requests.get(endpoint_comments)
+
+ return {"comments": comments.json()[:10], "statusCode": 200}
+ except parameters.exceptions.GetParameterError as error:
+ return {"comments": None, "message": str(error), "statusCode": 400}
diff --git a/examples/parameters/tests/src/__init__.py b/examples/parameters/tests/src/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/examples/parameters/tests/src/app.py b/examples/parameters/tests/src/app.py
new file mode 100644
index 00000000000..b505749e31b
--- /dev/null
+++ b/examples/parameters/tests/src/app.py
@@ -0,0 +1,10 @@
+from botocore.config import Config
+
+from aws_lambda_powertools.utilities import parameters
+
+ssm_provider = parameters.SSMProvider(config=Config(region_name="us-west-1"))
+
+
+def handler(event, context):
+ value = ssm_provider.get("/my/parameter")
+ return {"message": value}
diff --git a/examples/parameters/tests/src/single_mock.py b/examples/parameters/tests/src/single_mock.py
new file mode 100644
index 00000000000..ef94df54f25
--- /dev/null
+++ b/examples/parameters/tests/src/single_mock.py
@@ -0,0 +1,7 @@
+from aws_lambda_powertools.utilities import parameters
+
+
+def handler(event, context):
+ # Retrieve a single parameter
+ value = parameters.get_parameter("my-parameter-name")
+ return {"message": value}
diff --git a/examples/parameters/tests/test_clear_cache_global.py b/examples/parameters/tests/test_clear_cache_global.py
new file mode 100644
index 00000000000..5b07f40caed
--- /dev/null
+++ b/examples/parameters/tests/test_clear_cache_global.py
@@ -0,0 +1,24 @@
+import pytest
+import src.app as app
+
+from aws_lambda_powertools.utilities import parameters
+
+
+@pytest.fixture(scope="function", autouse=True)
+def clear_parameters_cache():
+ yield
+ parameters.clear_caches() # This will clear all providers cache
+
+
+@pytest.fixture
+def mock_parameter_response(monkeypatch):
+ def mockreturn(name):
+ return "mock_value"
+
+ monkeypatch.setattr(app.ssm_provider, "get", mockreturn)
+
+
+# Pass our fixture as an argument to all tests where we want to mock the get_parameter response
+def test_handler(mock_parameter_response):
+ return_val = app.handler({}, {})
+ assert return_val.get("message") == "mock_value"
diff --git a/examples/parameters/tests/test_clear_cache_method.py b/examples/parameters/tests/test_clear_cache_method.py
new file mode 100644
index 00000000000..da1eb181c68
--- /dev/null
+++ b/examples/parameters/tests/test_clear_cache_method.py
@@ -0,0 +1,22 @@
+import pytest
+import src.app as app
+
+
+@pytest.fixture(scope="function", autouse=True)
+def clear_parameters_cache():
+ yield
+ app.ssm_provider.clear_cache() # This will clear SSMProvider cache
+
+
+@pytest.fixture
+def mock_parameter_response(monkeypatch):
+ def mockreturn(name):
+ return "mock_value"
+
+ monkeypatch.setattr(app.ssm_provider, "get", mockreturn)
+
+
+# Pass our fixture as an argument to all tests where we want to mock the get_parameter response
+def test_handler(mock_parameter_response):
+ return_val = app.handler({}, {})
+ assert return_val.get("message") == "mock_value"
diff --git a/examples/parameters/tests/test_single_mock.py b/examples/parameters/tests/test_single_mock.py
new file mode 100644
index 00000000000..c4d045be499
--- /dev/null
+++ b/examples/parameters/tests/test_single_mock.py
@@ -0,0 +1,10 @@
+import src.single_mock as single_mock
+
+
+def test_handler(monkeypatch):
+ def mockreturn(name):
+ return "mock_value"
+
+ monkeypatch.setattr(single_mock.parameters, "get_parameter", mockreturn)
+ return_val = single_mock.handler({}, {})
+ assert return_val.get("message") == "mock_value"
diff --git a/examples/parameters/tests/test_with_fixture.py b/examples/parameters/tests/test_with_fixture.py
new file mode 100644
index 00000000000..0d29ad28030
--- /dev/null
+++ b/examples/parameters/tests/test_with_fixture.py
@@ -0,0 +1,16 @@
+import pytest
+import src.single_mock as single_mock
+
+
+@pytest.fixture
+def mock_parameter_response(monkeypatch):
+ def mockreturn(name):
+ return "mock_value"
+
+ monkeypatch.setattr(single_mock.parameters, "get_parameter", mockreturn)
+
+
+# Pass our fixture as an argument to all tests where we want to mock the get_parameter response
+def test_handler(mock_parameter_response):
+ return_val = single_mock.handler({}, {})
+ assert return_val.get("message") == "mock_value"
diff --git a/examples/parameters/tests/test_with_monkeypatch.py b/examples/parameters/tests/test_with_monkeypatch.py
new file mode 100644
index 00000000000..71ac4b406ed
--- /dev/null
+++ b/examples/parameters/tests/test_with_monkeypatch.py
@@ -0,0 +1,13 @@
+from unittest.mock import patch
+
+import src.single_mock as single_mock
+
+
+# Replaces "aws_lambda_powertools.utilities.parameters.get_parameter" with a Mock object
+@patch("aws_lambda_powertools.utilities.parameters.get_parameter")
+def test_handler(get_parameter_mock):
+ get_parameter_mock.return_value = "mock_value"
+
+ return_val = single_mock.handler({}, {})
+ get_parameter_mock.assert_called_with("my-parameter-name")
+ assert return_val.get("message") == "mock_value"
diff --git a/mypy.ini b/mypy.ini
index 6ab4cb0de32..fd14881dfb1 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -53,5 +53,8 @@ ignore_missing_imports = True
[mypy-snappy]
ignore_missing_imports = True
+[mypy-hvac]
+ignore_missing_imports = True
+
[mypy-ijson]
ignore_missing_imports = True
diff --git a/package-lock.json b/package-lock.json
index 1764eda669e..f466bfd38a1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,13 +8,13 @@
"name": "aws-lambda-powertools-python-e2e",
"version": "1.0.0",
"devDependencies": {
- "aws-cdk": "2.44.0"
+ "aws-cdk": "2.61.1"
}
},
"node_modules/aws-cdk": {
- "version": "2.44.0",
- "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.44.0.tgz",
- "integrity": "sha512-9hbK4Yc1GQ28zSjZE2ajidt7sRrTLYpijkI7HT7JcDhXLe2ZGP9EOZrqKy5EEsOv0wDQ7cdXB3/oMiMGSmSQ5A==",
+ "version": "2.61.1",
+ "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.61.1.tgz",
+ "integrity": "sha512-bufvOB+I2T6YjVjT6D0j6xbi6CnX62j7TfHL905WLd5UQhPecwlL8wLe2whUOKqZj2wmGjaP7jAjIE1FFfh98w==",
"dev": true,
"bin": {
"cdk": "bin/cdk"
@@ -43,9 +43,9 @@
},
"dependencies": {
"aws-cdk": {
- "version": "2.44.0",
- "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.44.0.tgz",
- "integrity": "sha512-9hbK4Yc1GQ28zSjZE2ajidt7sRrTLYpijkI7HT7JcDhXLe2ZGP9EOZrqKy5EEsOv0wDQ7cdXB3/oMiMGSmSQ5A==",
+ "version": "2.61.1",
+ "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.61.1.tgz",
+ "integrity": "sha512-bufvOB+I2T6YjVjT6D0j6xbi6CnX62j7TfHL905WLd5UQhPecwlL8wLe2whUOKqZj2wmGjaP7jAjIE1FFfh98w==",
"dev": true,
"requires": {
"fsevents": "2.3.2"
diff --git a/package.json b/package.json
index 6d5eb3f5bee..1d9a62c13d9 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,6 @@
"name": "aws-lambda-powertools-python-e2e",
"version": "1.0.0",
"devDependencies": {
- "aws-cdk": "2.44.0"
+ "aws-cdk": "2.61.1"
}
}
diff --git a/parallel_run_e2e.py b/parallel_run_e2e.py
index 745f1392f67..1146f66931e 100755
--- a/parallel_run_e2e.py
+++ b/parallel_run_e2e.py
@@ -1,5 +1,6 @@
""" Calculate how many parallel workers are needed to complete E2E infrastructure jobs across available CPU Cores """
import subprocess
+import sys
from pathlib import Path
@@ -7,8 +8,9 @@ def main():
features = Path("tests/e2e").rglob("infrastructure.py")
workers = len(list(features)) - 1
- command = f"poetry run pytest -n {workers} --dist loadfile -o log_cli=true tests/e2e"
- subprocess.run(command.split(), shell=False)
+ command = f"poetry run pytest -n {workers} -o log_cli=true tests/e2e"
+ result = subprocess.run(command.split(), shell=False)
+ sys.exit(result.returncode)
if __name__ == "__main__":
diff --git a/poetry.lock b/poetry.lock
index 8b7320b4381..379a24bb5e5 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -2,36 +2,37 @@
[[package]]
name = "attrs"
-version = "22.1.0"
+version = "22.2.0"
description = "Classes Without Boilerplate"
category = "dev"
optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
files = [
- {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
- {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
+ {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
+ {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
]
[package.extras]
-dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
-docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
-tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
-tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
+cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
+dev = ["attrs[docs,tests]"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
+tests = ["attrs[tests-no-zope]", "zope.interface"]
+tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
[[package]]
name = "aws-cdk-asset-awscli-v1"
-version = "2.2.49"
+version = "2.2.52"
description = "A library that contains the AWS CLI for use in Lambda Layers"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "aws-cdk.asset-awscli-v1-2.2.49.tar.gz", hash = "sha256:d367da8bdc83357792b1ef16b6166d400ef15f2389cf0032b607b6327768a41a"},
- {file = "aws_cdk.asset_awscli_v1-2.2.49-py3-none-any.whl", hash = "sha256:28df4487e2fa5314d5c39c114e12d366714a1fab2de3269d55c4e544876cae44"},
+ {file = "aws-cdk.asset-awscli-v1-2.2.52.tar.gz", hash = "sha256:ab04beec8e267e363931df2caf48a24100cb5799d7fd8db51efe881d117efa7a"},
+ {file = "aws_cdk.asset_awscli_v1-2.2.52-py3-none-any.whl", hash = "sha256:6e9d686bb0b00242e869e91d57b65b619ffb42e99abe482436e3a6692485dbfe"},
]
[package.dependencies]
-jsii = ">=1.72.0,<2.0.0"
+jsii = ">=1.73.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
@@ -54,70 +55,90 @@ typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "aws-cdk-asset-node-proxy-agent-v5"
-version = "2.0.38"
+version = "2.0.42"
description = "@aws-cdk/asset-node-proxy-agent-v5"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "aws-cdk.asset-node-proxy-agent-v5-2.0.38.tar.gz", hash = "sha256:eb80e0098899bd29e4f0938c68802cc022a8e39af8c05de4053f9a209e63bb7c"},
- {file = "aws_cdk.asset_node_proxy_agent_v5-2.0.38-py3-none-any.whl", hash = "sha256:0add1debe24e566b8d2cf713ca85eb5e82c42de00f737dfbf02e18e22220a41b"},
+ {file = "aws-cdk.asset-node-proxy-agent-v5-2.0.42.tar.gz", hash = "sha256:ae1b615be42e78681e05b145460603f171c06b671a2d1caa060a159b94b06366"},
+ {file = "aws_cdk.asset_node_proxy_agent_v5-2.0.42-py3-none-any.whl", hash = "sha256:6e0174802097d558daa1be5c4e6e7f309eeba626392955e596bf967ee37865d3"},
]
[package.dependencies]
-jsii = ">=1.72.0,<2.0.0"
+jsii = ">=1.73.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "aws-cdk-aws-apigatewayv2-alpha"
-version = "2.53.0a0"
+version = "2.62.2a0"
description = "The CDK Construct Library for AWS::APIGatewayv2"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "aws-cdk.aws-apigatewayv2-alpha-2.53.0a0.tar.gz", hash = "sha256:7bfd688d3c22676266ff161012f11ff3f60e11e50ba0d39d18a313ff07f69bbd"},
- {file = "aws_cdk.aws_apigatewayv2_alpha-2.53.0a0-py3-none-any.whl", hash = "sha256:6864d15ea12c903ae6ca679aaec49dd6c65fc1b537cd317c62cd334f7a382683"},
+ {file = "aws-cdk.aws-apigatewayv2-alpha-2.62.2a0.tar.gz", hash = "sha256:63c191fdcb8b20d1afd34af84ae465740b14009a06af7bdc8e78475614f85a23"},
+ {file = "aws_cdk.aws_apigatewayv2_alpha-2.62.2a0-py3-none-any.whl", hash = "sha256:32ff5d8745b71ef30ba009de4d8d9f12bd34a4f3c940500ba34367211f05c9f4"},
+]
+
+[package.dependencies]
+aws-cdk-lib = ">=2.62.2,<3.0.0"
+constructs = ">=10.0.0,<11.0.0"
+jsii = ">=1.73.0,<2.0.0"
+publication = ">=0.0.3"
+typeguard = ">=2.13.3,<2.14.0"
+
+[[package]]
+name = "aws-cdk-aws-apigatewayv2-authorizers-alpha"
+version = "2.62.2a0"
+description = "Authorizers for AWS APIGateway V2"
+category = "dev"
+optional = false
+python-versions = "~=3.7"
+files = [
+ {file = "aws-cdk.aws-apigatewayv2-authorizers-alpha-2.62.2a0.tar.gz", hash = "sha256:9a4ba121c49e4ba866b985495b87e9ecaec50c1f26e0d8cb116e15492196c042"},
+ {file = "aws_cdk.aws_apigatewayv2_authorizers_alpha-2.62.2a0-py3-none-any.whl", hash = "sha256:9cfb1495b618880b395d6ecbd45c3c524c67013f2567eae6e19e6f06586b9a38"},
]
[package.dependencies]
-aws-cdk-lib = ">=2.53.0,<3.0.0"
+"aws-cdk.aws-apigatewayv2-alpha" = "2.62.2.a0"
+aws-cdk-lib = ">=2.62.2,<3.0.0"
constructs = ">=10.0.0,<11.0.0"
-jsii = ">=1.71.0,<2.0.0"
+jsii = ">=1.73.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "aws-cdk-aws-apigatewayv2-integrations-alpha"
-version = "2.53.0a0"
+version = "2.62.2a0"
description = "Integrations for AWS APIGateway V2"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "aws-cdk.aws-apigatewayv2-integrations-alpha-2.53.0a0.tar.gz", hash = "sha256:fb8bf5812908787a776a9dc5a13bbacec0b39f07517f9a57ebba33d9585ab131"},
- {file = "aws_cdk.aws_apigatewayv2_integrations_alpha-2.53.0a0-py3-none-any.whl", hash = "sha256:4419283b9a0f41c0cfc5e4a8ba0b0236ca948d874c1c165f058c2c1677ffe6d1"},
+ {file = "aws-cdk.aws-apigatewayv2-integrations-alpha-2.62.2a0.tar.gz", hash = "sha256:4ae06b6585664c659eb6b88ff70eaa628a96ffb4728ab0d0eb7ff1f23913565b"},
+ {file = "aws_cdk.aws_apigatewayv2_integrations_alpha-2.62.2a0-py3-none-any.whl", hash = "sha256:497e93d193895b1b38545d5ca152e31f575b971ce371ad655aeb3bbed7fc6052"},
]
[package.dependencies]
-"aws-cdk.aws-apigatewayv2-alpha" = "2.53.0.a0"
-aws-cdk-lib = ">=2.53.0,<3.0.0"
+"aws-cdk.aws-apigatewayv2-alpha" = "2.62.2.a0"
+aws-cdk-lib = ">=2.62.2,<3.0.0"
constructs = ">=10.0.0,<11.0.0"
-jsii = ">=1.71.0,<2.0.0"
+jsii = ">=1.73.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "aws-cdk-lib"
-version = "2.61.1"
+version = "2.62.2"
description = "Version 2 of the AWS Cloud Development Kit library"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "aws-cdk-lib-2.61.1.tar.gz", hash = "sha256:d2bb672be182e0cd675717648fa100e1a49f01de606ffa4f7a0b580093f31b27"},
- {file = "aws_cdk_lib-2.61.1-py3-none-any.whl", hash = "sha256:e0b5d49c73be945ca176b38ff3d2ccfc9474639000afb6af65a1eaf8b6aa3385"},
+ {file = "aws-cdk-lib-2.62.2.tar.gz", hash = "sha256:f85000438d849a0522ffcd8e7cb5a70be5fa34339082d4d569734169c6d37b4d"},
+ {file = "aws_cdk_lib-2.62.2-py3-none-any.whl", hash = "sha256:03dfb8303b00333177b18e3b60c95d738adf4d90086a5b1e707e896fdc234d52"},
]
[package.dependencies]
@@ -129,25 +150,42 @@ jsii = ">=1.73.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
+[[package]]
+name = "aws-requests-auth"
+version = "0.4.3"
+description = "AWS signature version 4 signing process for the python requests module"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "aws-requests-auth-0.4.3.tar.gz", hash = "sha256:33593372018b960a31dbbe236f89421678b885c35f0b6a7abfae35bb77e069b2"},
+ {file = "aws_requests_auth-0.4.3-py2.py3-none-any.whl", hash = "sha256:646bc37d62140ea1c709d20148f5d43197e6bd2d63909eb36fa4bb2345759977"},
+]
+
+[package.dependencies]
+requests = ">=0.14.0"
+
[[package]]
name = "aws-sam-translator"
-version = "1.55.0"
+version = "1.58.1"
description = "AWS SAM Translator is a library that transform SAM templates into AWS CloudFormation templates"
category = "dev"
optional = false
python-versions = ">=3.7, <=4.0, !=4.0"
files = [
- {file = "aws-sam-translator-1.55.0.tar.gz", hash = "sha256:08e182e76d6fabc13ce2f38b8a3932b3131407c6ad29ec2849ef3d9a41576b94"},
- {file = "aws_sam_translator-1.55.0-py2-none-any.whl", hash = "sha256:e86a67b87329a0de7d531d33257d1a448d0d6ecd84aee058d084957f28a8e4b1"},
- {file = "aws_sam_translator-1.55.0-py3-none-any.whl", hash = "sha256:93dc74614ab291c86be681e025679d08f4fa685ed6b55d410f62f2f235012205"},
+ {file = "aws-sam-translator-1.58.1.tar.gz", hash = "sha256:cd60a19085d432bc00769b597bc2e6854f546ff9928f8067fc5fbcb5a1ed74ff"},
+ {file = "aws_sam_translator-1.58.1-py2-none-any.whl", hash = "sha256:c4e261e450d574572d389edcafab04d1fe337615f867610410390c2435cb1f26"},
+ {file = "aws_sam_translator-1.58.1-py3-none-any.whl", hash = "sha256:ca47d6eb04d8cf358bea9160411193da40a80dc3e79bb0c5bace0c21f0e4c888"},
]
[package.dependencies]
boto3 = ">=1.19.5,<2.0.0"
-jsonschema = ">=3.2,<4.0"
+jsonschema = ">=3.2,<5"
+pydantic = ">=1.10.2,<1.11.0"
+typing-extensions = ">=4.4.0,<4.5.0"
[package.extras]
-dev = ["black (==20.8b1)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.0.0)", "click (>=7.1,<8.0)", "coverage (>=5.3,<6.0)", "dateparser (>=0.7,<1.0)", "docopt (>=0.6.2,<0.7.0)", "flake8 (>=3.8.4,<3.9.0)", "mypy (==0.971)", "parameterized (>=0.7.4,<0.8.0)", "pylint (>=2.15.0,<2.16.0)", "pytest (>=6.2.5,<6.3.0)", "pytest-cov (>=2.10.1,<2.11.0)", "pytest-env (>=0.6.2,<0.7.0)", "pytest-rerunfailures (>=9.1.1,<9.2.0)", "pytest-xdist (>=2.5,<3.0)", "pyyaml (>=5.4,<6.0)", "requests (>=2.24.0,<2.25.0)", "ruamel.yaml (==0.17.21)", "tenacity (>=7.0.0,<7.1.0)", "tox (>=3.24,<4.0)", "types-PyYAML (>=5.4,<6.0)", "types-jsonschema (>=3.2,<4.0)"]
+dev = ["black (==20.8b1)", "boto3 (>=1.23,<2)", "boto3-stubs[appconfig,serverlessrepo] (>=1.19.5,<2.0.0)", "click (>=7.1,<8.0)", "coverage (>=5.3,<6.0)", "dateparser (>=0.7,<1.0)", "docopt (>=0.6.2,<0.7.0)", "flake8 (>=3.8.4,<3.9.0)", "mypy (==0.971)", "parameterized (>=0.7.4,<0.8.0)", "pylint (>=2.15.0,<2.16.0)", "pytest (>=6.2.5,<6.3.0)", "pytest-cov (>=2.10.1,<2.11.0)", "pytest-env (>=0.6.2,<0.7.0)", "pytest-rerunfailures (>=9.1.1,<9.2.0)", "pytest-xdist (>=2.5,<3.0)", "pyyaml (>=5.4,<6.0)", "requests (>=2.25.0,<2.26.0)", "ruamel.yaml (==0.17.21)", "tenacity (>=7.0.0,<7.1.0)", "tox (>=3.24,<4.0)", "types-PyYAML (>=5.4,<6.0)", "types-jsonschema (>=3.2,<4.0)"]
[[package]]
name = "aws-xray-sdk"
@@ -227,18 +265,18 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "boto3"
-version = "1.26.18"
+version = "1.26.60"
description = "The AWS SDK for Python"
category = "main"
optional = false
python-versions = ">= 3.7"
files = [
- {file = "boto3-1.26.18-py3-none-any.whl", hash = "sha256:933c88b189112a5fdd82d49ef00f95b9dd649d195e557a81aecb773a3e01c517"},
- {file = "boto3-1.26.18.tar.gz", hash = "sha256:3c7315da16eb0b41823965e5ce55f99cb07e94680e0ed7830c581f505fb5bd15"},
+ {file = "boto3-1.26.60-py3-none-any.whl", hash = "sha256:5fd2810217a74a38078a19fb85a9e5d6934d0c146eb060967a3ffd7ab33cdf00"},
+ {file = "boto3-1.26.60.tar.gz", hash = "sha256:f0824b3bcf803800d3ecef903b4840427e4b3d37a069f6fc9a86310f7e036ad5"},
]
[package.dependencies]
-botocore = ">=1.29.18,<1.30.0"
+botocore = ">=1.29.60,<1.30.0"
jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.6.0,<0.7.0"
@@ -247,14 +285,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]]
name = "botocore"
-version = "1.29.18"
+version = "1.29.60"
description = "Low-level, data-driven core of boto 3."
category = "main"
optional = false
python-versions = ">= 3.7"
files = [
- {file = "botocore-1.29.18-py3-none-any.whl", hash = "sha256:2aba44433b6eac6d3a12cf93f2985e2d7a843307c1a527042fc48dd09b273992"},
- {file = "botocore-1.29.18.tar.gz", hash = "sha256:26e86fce95049f6cc18b5611901549943c4c22522fa8a3b6b265404f673977b2"},
+ {file = "botocore-1.29.60-py3-none-any.whl", hash = "sha256:c4ae251e7df0cf01d893eb945bc8f23c14989ed349775a8e16c949f08a068f9a"},
+ {file = "botocore-1.29.60.tar.gz", hash = "sha256:a21217ccf4613c9ebbe4c3192e13ba91d46be642560e39a16406662a398a107b"},
]
[package.dependencies]
@@ -263,7 +301,7 @@ python-dateutil = ">=2.1,<3.0.0"
urllib3 = ">=1.25.4,<1.27"
[package.extras]
-crt = ["awscrt (==0.14.0)"]
+crt = ["awscrt (==0.15.3)"]
[[package]]
name = "cattrs"
@@ -318,19 +356,102 @@ sarif-om = ">=1.0.4,<1.1.0"
[[package]]
name = "charset-normalizer"
-version = "2.1.1"
+version = "3.0.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "dev"
optional = false
-python-versions = ">=3.6.0"
+python-versions = "*"
files = [
- {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
- {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
+ {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"},
+ {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"},
+ {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"},
+ {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"},
+ {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"},
+ {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"},
+ {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"},
+ {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"},
]
-[package.extras]
-unicode-backport = ["unicodedata2"]
-
[[package]]
name = "checksumdir"
version = "1.2.0"
@@ -373,80 +494,80 @@ files = [
[[package]]
name = "constructs"
-version = "10.1.174"
+version = "10.1.236"
description = "A programming model for software-defined state"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "constructs-10.1.174-py3-none-any.whl", hash = "sha256:6968efd5f837f3a43d5a93808424744cdcd03f53df764be78123f60e81b39b0a"},
- {file = "constructs-10.1.174.tar.gz", hash = "sha256:af9bd1f0bd6882a6a608bc335a4f8a230f498072bff83d9126d43c486e30305b"},
+ {file = "constructs-10.1.236-py3-none-any.whl", hash = "sha256:e51d8fac38b12a88359d5d2bedb535987eaa54e68631add29726652be66490e9"},
+ {file = "constructs-10.1.236.tar.gz", hash = "sha256:10b3c5ed3d4c6fd930bd8f59c8a5926028dafe8a5bf703fba5bcc53c89fce002"},
]
[package.dependencies]
-jsii = ">=1.71.0,<2.0.0"
+jsii = ">=1.74.0,<2.0.0"
publication = ">=0.0.3"
typeguard = ">=2.13.3,<2.14.0"
[[package]]
name = "coverage"
-version = "7.0.5"
+version = "7.1.0"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"},
- {file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"},
- {file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"},
- {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"},
- {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"},
- {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"},
- {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"},
- {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"},
- {file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"},
- {file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"},
- {file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"},
- {file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"},
- {file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"},
- {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"},
- {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"},
- {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"},
- {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"},
- {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"},
- {file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"},
- {file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"},
- {file = "coverage-7.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b69522b168a6b64edf0c33ba53eac491c0a8f5cc94fa4337f9c6f4c8f2f5296c"},
- {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436e103950d05b7d7f55e39beeb4d5be298ca3e119e0589c0227e6d0b01ee8c7"},
- {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c56bec53d6e3154eaff6ea941226e7bd7cc0d99f9b3756c2520fc7a94e6d96"},
- {file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a38362528a9115a4e276e65eeabf67dcfaf57698e17ae388599568a78dcb029"},
- {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f67472c09a0c7486e27f3275f617c964d25e35727af952869dd496b9b5b7f6a3"},
- {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:220e3fa77d14c8a507b2d951e463b57a1f7810a6443a26f9b7591ef39047b1b2"},
- {file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecb0f73954892f98611e183f50acdc9e21a4653f294dfbe079da73c6378a6f47"},
- {file = "coverage-7.0.5-cp37-cp37m-win32.whl", hash = "sha256:d8f3e2e0a1d6777e58e834fd5a04657f66affa615dae61dd67c35d1568c38882"},
- {file = "coverage-7.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9e662e6fc4f513b79da5d10a23edd2b87685815b337b1a30cd11307a6679148d"},
- {file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"},
- {file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"},
- {file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"},
- {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"},
- {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"},
- {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"},
- {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"},
- {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"},
- {file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"},
- {file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"},
- {file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"},
- {file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"},
- {file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"},
- {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"},
- {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"},
- {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"},
- {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"},
- {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"},
- {file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"},
- {file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"},
- {file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"},
- {file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"},
+ {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"},
+ {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"},
+ {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"},
+ {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"},
+ {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"},
+ {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"},
+ {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"},
+ {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"},
+ {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"},
+ {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"},
+ {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"},
+ {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"},
+ {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"},
+ {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"},
+ {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"},
+ {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"},
+ {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"},
+ {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"},
+ {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"},
+ {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"},
+ {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"},
+ {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"},
+ {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"},
+ {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"},
+ {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"},
+ {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"},
+ {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"},
+ {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"},
+ {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"},
+ {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"},
+ {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"},
+ {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"},
+ {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"},
+ {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"},
+ {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"},
+ {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"},
+ {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"},
+ {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"},
+ {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"},
+ {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"},
+ {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"},
+ {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"},
+ {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"},
+ {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"},
+ {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"},
+ {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"},
+ {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"},
+ {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"},
+ {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"},
+ {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"},
+ {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"},
]
[package.dependencies]
@@ -481,14 +602,14 @@ files = [
[[package]]
name = "exceptiongroup"
-version = "1.0.4"
+version = "1.1.0"
description = "Backport of PEP 654 (exception groups)"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"},
- {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"},
+ {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"},
+ {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"},
]
[package.extras]
@@ -597,14 +718,14 @@ develop = ["build", "twine"]
[[package]]
name = "flake8-bugbear"
-version = "22.12.6"
+version = "23.1.20"
description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "flake8-bugbear-22.12.6.tar.gz", hash = "sha256:4cdb2c06e229971104443ae293e75e64c6107798229202fbe4f4091427a30ac0"},
- {file = "flake8_bugbear-22.12.6-py3-none-any.whl", hash = "sha256:b69a510634f8a9c298dfda2b18a8036455e6b19ecac4fe582e4d7a0abfa50a30"},
+ {file = "flake8-bugbear-23.1.20.tar.gz", hash = "sha256:55902ab5a48c5ea53d8689ecd146eda548e72f2724192b9c1d68f6d975d13c06"},
+ {file = "flake8_bugbear-23.1.20-py3-none-any.whl", hash = "sha256:04a115e5f9c8e87c38bdbbcdf9f58223ffe05469c07c9a7bd8633330bc4d078b"},
]
[package.dependencies]
@@ -612,7 +733,7 @@ attrs = ">=19.2.0"
flake8 = ">=3.0.0"
[package.extras]
-dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"]
+dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"]
[[package]]
name = "flake8-builtins"
@@ -766,6 +887,22 @@ files = [
gitdb = ">=4.0.1,<5"
typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""}
+[[package]]
+name = "hvac"
+version = "1.0.2"
+description = "HashiCorp Vault API client"
+category = "dev"
+optional = false
+python-versions = ">=3.6.2,<4.0.0"
+files = [
+ {file = "hvac-1.0.2-py3-none-any.whl", hash = "sha256:e8256343de2576b18bc8d49f09a04c728f2a8f3a866825bb413aa4f9ebab1fea"},
+ {file = "hvac-1.0.2.tar.gz", hash = "sha256:e4028c5c0ecc7b7fcf6a54d290f99240e5abcdb9ffe442d1c14f061310d4c61c"},
+]
+
+[package.dependencies]
+pyhcl = ">=0.4.4,<0.5.0"
+requests = ">=2.27.1,<3.0.0"
+
[[package]]
name = "idna"
version = "3.4"
@@ -887,33 +1024,52 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker
perf = ["ipython"]
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
+[[package]]
+name = "importlib-resources"
+version = "5.10.2"
+description = "Read resources from Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "importlib_resources-5.10.2-py3-none-any.whl", hash = "sha256:7d543798b0beca10b6a01ac7cafda9f822c54db9e8376a6bf57e0cbd74d486b6"},
+ {file = "importlib_resources-5.10.2.tar.gz", hash = "sha256:e4a96c8cc0339647ff9a5e0550d9f276fc5a01ffa276012b58ec108cfd7b8484"},
+]
+
+[package.dependencies]
+zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+
[[package]]
name = "iniconfig"
-version = "1.1.1"
-description = "iniconfig: brain-dead simple config-ini parsing"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.7"
files = [
- {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
- {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "isort"
-version = "5.11.4"
+version = "5.11.5"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=3.7.0"
files = [
- {file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"},
- {file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"},
+ {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"},
+ {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"},
]
[package.extras]
colors = ["colorama (>=0.4.3,<0.5.0)"]
-pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
+pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
@@ -966,14 +1122,14 @@ pbr = "*"
[[package]]
name = "jsii"
-version = "1.73.0"
+version = "1.74.0"
description = "Python client for jsii runtime"
category = "dev"
optional = false
python-versions = "~=3.7"
files = [
- {file = "jsii-1.73.0-py3-none-any.whl", hash = "sha256:13e8496c3afee70d85401ad1eef2ddedbdb88e7e7abb3e68302dd6e61527191e"},
- {file = "jsii-1.73.0.tar.gz", hash = "sha256:be6458236e787be0b02c2fe869b6f4ed906398b6cc537190d61a60d2b5c9dfbb"},
+ {file = "jsii-1.74.0-py3-none-any.whl", hash = "sha256:ee76781fe66106c367fbb3bb383db4f5e9b8ff3d3c4c0f34624c050211f040be"},
+ {file = "jsii-1.74.0.tar.gz", hash = "sha256:575131396ad34f8f6e9f2604953ecbf4f3368625656a828b13089e4abb81b443"},
]
[package.dependencies]
@@ -1001,14 +1157,14 @@ jsonpointer = ">=1.9"
[[package]]
name = "jsonpickle"
-version = "2.2.0"
+version = "3.0.1"
description = "Python library for serializing any arbitrary object graph into JSON"
category = "dev"
optional = false
-python-versions = ">=2.7"
+python-versions = ">=3.7"
files = [
- {file = "jsonpickle-2.2.0-py2.py3-none-any.whl", hash = "sha256:de7f2613818aa4f234138ca11243d6359ff83ae528b2185efdd474f62bcf9ae1"},
- {file = "jsonpickle-2.2.0.tar.gz", hash = "sha256:7b272918b0554182e53dc340ddd62d9b7f902fec7e7b05620c04f3ccef479a0e"},
+ {file = "jsonpickle-3.0.1-py2.py3-none-any.whl", hash = "sha256:130d8b293ea0add3845de311aaba55e6d706d0bb17bc123bd2c8baf8a39ac77c"},
+ {file = "jsonpickle-3.0.1.tar.gz", hash = "sha256:032538804795e73b94ead410800ac387fdb6de98f8882ac957fcd247e3a85200"},
]
[package.dependencies]
@@ -1016,8 +1172,8 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"]
-testing = ["ecdsa", "enum34", "feedparser", "jsonlib", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (<1.1.0)", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"]
-testing-libs = ["simplejson", "ujson", "yajl"]
+testing = ["ecdsa", "feedparser", "gmpy2", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"]
+testing-libs = ["simplejson", "ujson"]
[[package]]
name = "jsonpointer"
@@ -1033,26 +1189,27 @@ files = [
[[package]]
name = "jsonschema"
-version = "3.2.0"
+version = "4.17.3"
description = "An implementation of JSON Schema validation for Python"
category = "dev"
optional = false
-python-versions = "*"
+python-versions = ">=3.7"
files = [
- {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"},
- {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"},
+ {file = "jsonschema-4.17.3-py3-none-any.whl", hash = "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"},
+ {file = "jsonschema-4.17.3.tar.gz", hash = "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d"},
]
[package.dependencies]
attrs = ">=17.4.0"
importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
-pyrsistent = ">=0.14.0"
-setuptools = "*"
-six = ">=1.11.0"
+importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
+pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""}
+pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2"
+typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
-format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
-format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
[[package]]
name = "junit-xml"
@@ -1127,52 +1284,62 @@ testing = ["coverage", "pyyaml"]
[[package]]
name = "markupsafe"
-version = "2.1.1"
+version = "2.1.2"
description = "Safely add untrusted strings to HTML/XML markup."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"},
- {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"},
- {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"},
- {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"},
- {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
- {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"},
+ {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"},
+ {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"},
+ {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"},
+ {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"},
+ {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"},
+ {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"},
]
[[package]]
@@ -1281,14 +1448,14 @@ mkdocs = ">=0.17"
[[package]]
name = "mkdocs-material"
-version = "9.0.6"
+version = "9.0.9"
description = "Documentation that simply works"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mkdocs_material-9.0.6-py3-none-any.whl", hash = "sha256:4a71195ddc100dddf07d4b23b53373f36c5f0f1010fa4ea301ca7a8e949dd9e7"},
- {file = "mkdocs_material-9.0.6.tar.gz", hash = "sha256:6065b573e38746dc267d7fc84252be31b73da955b2ce553687806b6030e51ee0"},
+ {file = "mkdocs_material-9.0.9-py3-none-any.whl", hash = "sha256:29ebb2aa81e8cfb39e497bdafcacf4cc4aaa20ae31ce334f520c317c5bead1ba"},
+ {file = "mkdocs_material-9.0.9.tar.gz", hash = "sha256:c8fa9b1f0fded744a42317e594e5c21f4e3b56f1a0497e7d16951b3bd47784bf"},
]
[package.dependencies]
@@ -1391,14 +1558,14 @@ typing-extensions = ">=4.1.0"
[[package]]
name = "mypy-boto3-cloudformation"
-version = "1.26.35.post1"
-description = "Type annotations for boto3.CloudFormation 1.26.35 service generated with mypy-boto3-builder 7.12.1"
+version = "1.26.60"
+description = "Type annotations for boto3.CloudFormation 1.26.60 service generated with mypy-boto3-builder 7.12.3"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mypy-boto3-cloudformation-1.26.35.post1.tar.gz", hash = "sha256:b6f35ed5c463946185ae10e15b38f0400a8d88d9faa0534d7b8478474eefdbd4"},
- {file = "mypy_boto3_cloudformation-1.26.35.post1-py3-none-any.whl", hash = "sha256:087ad75bc0760eddb6cf3ef524d079061a5b8af82c7300555ccec21255de420b"},
+ {file = "mypy-boto3-cloudformation-1.26.60.tar.gz", hash = "sha256:1966b0f521e73d8d043e2499f33e252c71a7dba79bf79d89cb4a0bd8a79180a0"},
+ {file = "mypy_boto3_cloudformation-1.26.60-py3-none-any.whl", hash = "sha256:30305e6055076acc48e4346f599b6b24e1b1281d95aabb4d8b335f3915a001fa"},
]
[package.dependencies]
@@ -1436,14 +1603,14 @@ typing-extensions = ">=4.1.0"
[[package]]
name = "mypy-boto3-lambda"
-version = "1.26.49"
-description = "Type annotations for boto3.Lambda 1.26.49 service generated with mypy-boto3-builder 7.12.3"
+version = "1.26.55"
+description = "Type annotations for boto3.Lambda 1.26.55 service generated with mypy-boto3-builder 7.12.3"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mypy-boto3-lambda-1.26.49.tar.gz", hash = "sha256:748222e6dfd602a667b76b9ce0e8c8b31664bc3bd78cc43363fb22ca2885b4c3"},
- {file = "mypy_boto3_lambda-1.26.49-py3-none-any.whl", hash = "sha256:ef346c1fbbc80a907c1d44f19ea9335f8c3889fb48766cb0f7e4439e339fae2b"},
+ {file = "mypy-boto3-lambda-1.26.55.tar.gz", hash = "sha256:357e80e81c1e6674a1d5d879f6f1578103d3825bb87a7d2c897e8626a0f95fc0"},
+ {file = "mypy_boto3_lambda-1.26.55-py3-none-any.whl", hash = "sha256:3df0dc3e24ec0c79b0bdd024d40694aa41d2a5e355f9441863657eb632567312"},
]
[package.dependencies]
@@ -1466,14 +1633,14 @@ typing-extensions = ">=4.1.0"
[[package]]
name = "mypy-boto3-s3"
-version = "1.26.0.post1"
-description = "Type annotations for boto3.S3 1.26.0 service generated with mypy-boto3-builder 7.11.10"
+version = "1.26.58"
+description = "Type annotations for boto3.S3 1.26.58 service generated with mypy-boto3-builder 7.12.3"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "mypy-boto3-s3-1.26.0.post1.tar.gz", hash = "sha256:6d7079f8c739dc993cbedad0736299c413b297814b73795a3855a79169ecc938"},
- {file = "mypy_boto3_s3-1.26.0.post1-py3-none-any.whl", hash = "sha256:7de2792ff0cc541b84cd46ff3a6aa2b6e5f267217f2203f27f6e4016bddc644d"},
+ {file = "mypy-boto3-s3-1.26.58.tar.gz", hash = "sha256:02aa9514877147da996ea62e9d3d326d6b33f46c9c20b26f1e45fd125ba03518"},
+ {file = "mypy_boto3_s3-1.26.58-py3-none-any.whl", hash = "sha256:34989e04ae85ae5e7b653ea28359e9caad12bdd7eac68071e2166409e5e39e66"},
]
[package.dependencies]
@@ -1557,41 +1724,38 @@ test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"]
[[package]]
name = "packaging"
-version = "21.3"
+version = "23.0"
description = "Core utilities for Python packages"
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
- {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
+ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
+ {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
]
-[package.dependencies]
-pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
-
[[package]]
name = "pathspec"
-version = "0.10.2"
+version = "0.11.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pathspec-0.10.2-py3-none-any.whl", hash = "sha256:88c2606f2c1e818b978540f73ecc908e13999c6c3a383daf3705652ae79807a5"},
- {file = "pathspec-0.10.2.tar.gz", hash = "sha256:8f6bf73e5758fd365ef5d58ce09ac7c27d2833a8d7da51712eac6e27e35141b0"},
+ {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"},
+ {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"},
]
[[package]]
name = "pbr"
-version = "5.11.0"
+version = "5.11.1"
description = "Python Build Reasonableness"
category = "dev"
optional = false
python-versions = ">=2.6"
files = [
- {file = "pbr-5.11.0-py2.py3-none-any.whl", hash = "sha256:db2317ff07c84c4c63648c9064a79fe9d9f5c7ce85a9099d4b6258b3db83225a"},
- {file = "pbr-5.11.0.tar.gz", hash = "sha256:b97bc6695b2aff02144133c2e7399d5885223d42b7912ffaec2ca3898e673bfe"},
+ {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"},
+ {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"},
]
[[package]]
@@ -1610,21 +1774,36 @@ files = [
mako = "*"
markdown = ">=3.0"
+[[package]]
+name = "pkgutil-resolve-name"
+version = "1.3.10"
+description = "Resolve a name to an object."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"},
+ {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"},
+]
+
[[package]]
name = "platformdirs"
-version = "2.5.4"
+version = "2.6.2"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "platformdirs-2.5.4-py3-none-any.whl", hash = "sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10"},
- {file = "platformdirs-2.5.4.tar.gz", hash = "sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7"},
+ {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"},
+ {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"},
]
+[package.dependencies]
+typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""}
+
[package.extras]
-docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"]
-test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
+docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
+test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
[[package]]
name = "pluggy"
@@ -1710,7 +1889,7 @@ name = "pydantic"
version = "1.10.4"
description = "Data validation and settings management using python type hints"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.7"
files = [
{file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"},
@@ -1798,65 +1977,66 @@ files = [
plugins = ["importlib-metadata"]
[[package]]
-name = "pymdown-extensions"
-version = "9.9.1"
-description = "Extension pack for Python Markdown."
+name = "pyhcl"
+version = "0.4.4"
+description = "HCL configuration parser for python"
category = "dev"
optional = false
-python-versions = ">=3.7"
+python-versions = "*"
files = [
- {file = "pymdown_extensions-9.9.1-py3-none-any.whl", hash = "sha256:8a8973933ab45b6fe8f5f8da1de25766356b1f91dee107bf4a34efd158dc340b"},
- {file = "pymdown_extensions-9.9.1.tar.gz", hash = "sha256:abed29926960bbb3b40f5ed5fa6375e29724d4e3cb86ced7c2bbd37ead1afeea"},
+ {file = "pyhcl-0.4.4.tar.gz", hash = "sha256:2d9b9dcdf1023d812bfed561ba72c99104c5b3f52e558d595130a44ce081b003"},
]
-[package.dependencies]
-markdown = ">=3.2"
-
[[package]]
-name = "pyparsing"
-version = "3.0.9"
-description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+name = "pymdown-extensions"
+version = "9.9.2"
+description = "Extension pack for Python Markdown."
category = "dev"
optional = false
-python-versions = ">=3.6.8"
+python-versions = ">=3.7"
files = [
- {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
- {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
+ {file = "pymdown_extensions-9.9.2-py3-none-any.whl", hash = "sha256:c3d804eb4a42b85bafb5f36436342a5ad38df03878bb24db8855a4aa8b08b765"},
+ {file = "pymdown_extensions-9.9.2.tar.gz", hash = "sha256:ebb33069bafcb64d5f5988043331d4ea4929325dc678a6bcf247ddfcf96499f8"},
]
-[package.extras]
-diagrams = ["jinja2", "railroad-diagrams"]
+[package.dependencies]
+markdown = ">=3.2"
[[package]]
name = "pyrsistent"
-version = "0.19.2"
+version = "0.19.3"
description = "Persistent/Functional/Immutable data structures"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "pyrsistent-0.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d6982b5a0237e1b7d876b60265564648a69b14017f3b5f908c5be2de3f9abb7a"},
- {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:187d5730b0507d9285a96fca9716310d572e5464cadd19f22b63a6976254d77a"},
- {file = "pyrsistent-0.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:055ab45d5911d7cae397dc418808d8802fb95262751872c841c170b0dbf51eed"},
- {file = "pyrsistent-0.19.2-cp310-cp310-win32.whl", hash = "sha256:456cb30ca8bff00596519f2c53e42c245c09e1a4543945703acd4312949bfd41"},
- {file = "pyrsistent-0.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:b39725209e06759217d1ac5fcdb510e98670af9e37223985f330b611f62e7425"},
- {file = "pyrsistent-0.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aede922a488861de0ad00c7630a6e2d57e8023e4be72d9d7147a9fcd2d30712"},
- {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879b4c2f4d41585c42df4d7654ddffff1239dc4065bc88b745f0341828b83e78"},
- {file = "pyrsistent-0.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c43bec251bbd10e3cb58ced80609c5c1eb238da9ca78b964aea410fb820d00d6"},
- {file = "pyrsistent-0.19.2-cp37-cp37m-win32.whl", hash = "sha256:d690b18ac4b3e3cab73b0b7aa7dbe65978a172ff94970ff98d82f2031f8971c2"},
- {file = "pyrsistent-0.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:3ba4134a3ff0fc7ad225b6b457d1309f4698108fb6b35532d015dca8f5abed73"},
- {file = "pyrsistent-0.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a178209e2df710e3f142cbd05313ba0c5ebed0a55d78d9945ac7a4e09d923308"},
- {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e371b844cec09d8dc424d940e54bba8f67a03ebea20ff7b7b0d56f526c71d584"},
- {file = "pyrsistent-0.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111156137b2e71f3a9936baf27cb322e8024dac3dc54ec7fb9f0bcf3249e68bb"},
- {file = "pyrsistent-0.19.2-cp38-cp38-win32.whl", hash = "sha256:e5d8f84d81e3729c3b506657dddfe46e8ba9c330bf1858ee33108f8bb2adb38a"},
- {file = "pyrsistent-0.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:9cd3e9978d12b5d99cbdc727a3022da0430ad007dacf33d0bf554b96427f33ab"},
- {file = "pyrsistent-0.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f1258f4e6c42ad0b20f9cfcc3ada5bd6b83374516cd01c0960e3cb75fdca6770"},
- {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21455e2b16000440e896ab99e8304617151981ed40c29e9507ef1c2e4314ee95"},
- {file = "pyrsistent-0.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd880614c6237243ff53a0539f1cb26987a6dc8ac6e66e0c5a40617296a045e"},
- {file = "pyrsistent-0.19.2-cp39-cp39-win32.whl", hash = "sha256:71d332b0320642b3261e9fee47ab9e65872c2bd90260e5d225dabeed93cbd42b"},
- {file = "pyrsistent-0.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:dec3eac7549869365fe263831f576c8457f6c833937c68542d08fde73457d291"},
- {file = "pyrsistent-0.19.2-py3-none-any.whl", hash = "sha256:ea6b79a02a28550c98b6ca9c35b9f492beaa54d7c5c9e9949555893c8a9234d0"},
- {file = "pyrsistent-0.19.2.tar.gz", hash = "sha256:bfa0351be89c9fcbcb8c9879b826f4353be10f58f8a677efab0c017bf7137ec2"},
+ {file = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"},
+ {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"},
+ {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"},
+ {file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"},
+ {file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"},
+ {file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"},
+ {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"},
+ {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"},
+ {file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"},
+ {file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"},
+ {file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"},
+ {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"},
+ {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"},
+ {file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"},
+ {file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"},
+ {file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"},
+ {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"},
+ {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"},
+ {file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"},
+ {file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"},
+ {file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"},
+ {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"},
+ {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"},
+ {file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"},
+ {file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"},
+ {file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"},
+ {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"},
]
[[package]]
@@ -2238,19 +2418,19 @@ files = [
[[package]]
name = "requests"
-version = "2.28.1"
+version = "2.28.2"
description = "Python HTTP for Humans."
category = "dev"
optional = false
python-versions = ">=3.7, <4"
files = [
- {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
- {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
+ {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"},
+ {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"},
]
[package.dependencies]
certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<3"
+charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
@@ -2308,23 +2488,6 @@ files = [
attrs = "*"
pbr = "*"
-[[package]]
-name = "setuptools"
-version = "65.6.3"
-description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "dev"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
- {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
-]
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
-
[[package]]
name = "six"
version = "1.16.0"
@@ -2480,14 +2643,14 @@ files = [
[[package]]
name = "urllib3"
-version = "1.26.13"
+version = "1.26.14"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
- {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
- {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
+ {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
+ {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
]
[package.extras]
@@ -2512,37 +2675,40 @@ test = ["coverage", "flake8 (>=3.7)", "mypy", "pretend", "pytest"]
[[package]]
name = "watchdog"
-version = "2.1.9"
+version = "2.2.1"
description = "Filesystem events monitoring"
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
- {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a735a990a1095f75ca4f36ea2ef2752c99e6ee997c46b0de507ba40a09bf7330"},
- {file = "watchdog-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b17d302850c8d412784d9246cfe8d7e3af6bcd45f958abb2d08a6f8bedf695d"},
- {file = "watchdog-2.1.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee3e38a6cc050a8830089f79cbec8a3878ec2fe5160cdb2dc8ccb6def8552658"},
- {file = "watchdog-2.1.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64a27aed691408a6abd83394b38503e8176f69031ca25d64131d8d640a307591"},
- {file = "watchdog-2.1.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:195fc70c6e41237362ba720e9aaf394f8178bfc7fa68207f112d108edef1af33"},
- {file = "watchdog-2.1.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bfc4d351e6348d6ec51df007432e6fe80adb53fd41183716017026af03427846"},
- {file = "watchdog-2.1.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8250546a98388cbc00c3ee3cc5cf96799b5a595270dfcfa855491a64b86ef8c3"},
- {file = "watchdog-2.1.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:117ffc6ec261639a0209a3252546b12800670d4bf5f84fbd355957a0595fe654"},
- {file = "watchdog-2.1.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:97f9752208f5154e9e7b76acc8c4f5a58801b338de2af14e7e181ee3b28a5d39"},
- {file = "watchdog-2.1.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:247dcf1df956daa24828bfea5a138d0e7a7c98b1a47cf1fa5b0c3c16241fcbb7"},
- {file = "watchdog-2.1.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:226b3c6c468ce72051a4c15a4cc2ef317c32590d82ba0b330403cafd98a62cfd"},
- {file = "watchdog-2.1.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d9820fe47c20c13e3c9dd544d3706a2a26c02b2b43c993b62fcd8011bcc0adb3"},
- {file = "watchdog-2.1.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:70af927aa1613ded6a68089a9262a009fbdf819f46d09c1a908d4b36e1ba2b2d"},
- {file = "watchdog-2.1.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed80a1628cee19f5cfc6bb74e173f1b4189eb532e705e2a13e3250312a62e0c9"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9f05a5f7c12452f6a27203f76779ae3f46fa30f1dd833037ea8cbc2887c60213"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_armv7l.whl", hash = "sha256:255bb5758f7e89b1a13c05a5bceccec2219f8995a3a4c4d6968fe1de6a3b2892"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_i686.whl", hash = "sha256:d3dda00aca282b26194bdd0adec21e4c21e916956d972369359ba63ade616153"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_ppc64.whl", hash = "sha256:186f6c55abc5e03872ae14c2f294a153ec7292f807af99f57611acc8caa75306"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:083171652584e1b8829581f965b9b7723ca5f9a2cd7e20271edf264cfd7c1412"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_s390x.whl", hash = "sha256:b530ae007a5f5d50b7fbba96634c7ee21abec70dc3e7f0233339c81943848dc1"},
- {file = "watchdog-2.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:4f4e1c4aa54fb86316a62a87b3378c025e228178d55481d30d857c6c438897d6"},
- {file = "watchdog-2.1.9-py3-none-win32.whl", hash = "sha256:5952135968519e2447a01875a6f5fc8c03190b24d14ee52b0f4b1682259520b1"},
- {file = "watchdog-2.1.9-py3-none-win_amd64.whl", hash = "sha256:7a833211f49143c3d336729b0020ffd1274078e94b0ae42e22f596999f50279c"},
- {file = "watchdog-2.1.9-py3-none-win_ia64.whl", hash = "sha256:ad576a565260d8f99d97f2e64b0f97a48228317095908568a9d5c786c829d428"},
- {file = "watchdog-2.1.9.tar.gz", hash = "sha256:43ce20ebb36a51f21fa376f76d1d4692452b2527ccd601950d69ed36b9e21609"},
+ {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"},
+ {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"},
+ {file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"},
+ {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:102a60093090fc3ff76c983367b19849b7cc24ec414a43c0333680106e62aae1"},
+ {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:748ca797ff59962e83cc8e4b233f87113f3cf247c23e6be58b8a2885c7337aa3"},
+ {file = "watchdog-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ccd8d84b9490a82b51b230740468116b8205822ea5fdc700a553d92661253a3"},
+ {file = "watchdog-2.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6e01d699cd260d59b84da6bda019dce0a3353e3fcc774408ae767fe88ee096b7"},
+ {file = "watchdog-2.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8586d98c494690482c963ffb24c49bf9c8c2fe0589cec4dc2f753b78d1ec301d"},
+ {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:adaf2ece15f3afa33a6b45f76b333a7da9256e1360003032524d61bdb4c422ae"},
+ {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83a7cead445008e880dbde833cb9e5cc7b9a0958edb697a96b936621975f15b9"},
+ {file = "watchdog-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8ac23ff2c2df4471a61af6490f847633024e5aa120567e08d07af5718c9d092"},
+ {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d0f29fd9f3f149a5277929de33b4f121a04cf84bb494634707cfa8ea8ae106a8"},
+ {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:967636031fa4c4955f0f3f22da3c5c418aa65d50908d31b73b3b3ffd66d60640"},
+ {file = "watchdog-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96cbeb494e6cbe3ae6aacc430e678ce4b4dd3ae5125035f72b6eb4e5e9eb4f4e"},
+ {file = "watchdog-2.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61fdb8e9c57baf625e27e1420e7ca17f7d2023929cd0065eb79c83da1dfbeacd"},
+ {file = "watchdog-2.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb5ecc332112017fbdb19ede78d92e29a8165c46b68a0b8ccbd0a154f196d5e"},
+ {file = "watchdog-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a480d122740debf0afac4ddd583c6c0bb519c24f817b42ed6f850e2f6f9d64a8"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:978a1aed55de0b807913b7482d09943b23a2d634040b112bdf31811a422f6344"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:8c28c23972ec9c524967895ccb1954bc6f6d4a557d36e681a36e84368660c4ce"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_i686.whl", hash = "sha256:c27d8c1535fd4474e40a4b5e01f4ba6720bac58e6751c667895cbc5c8a7af33c"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d6b87477752bd86ac5392ecb9eeed92b416898c30bd40c7e2dd03c3146105646"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cece1aa596027ff56369f0b50a9de209920e1df9ac6d02c7f9e5d8162eb4f02b"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:8b5cde14e5c72b2df5d074774bdff69e9b55da77e102a91f36ef26ca35f9819c"},
+ {file = "watchdog-2.2.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e038be858425c4f621900b8ff1a3a1330d9edcfeaa1c0468aeb7e330fb87693e"},
+ {file = "watchdog-2.2.1-py3-none-win32.whl", hash = "sha256:bc43c1b24d2f86b6e1cc15f68635a959388219426109233e606517ff7d0a5a73"},
+ {file = "watchdog-2.2.1-py3-none-win_amd64.whl", hash = "sha256:17f1708f7410af92ddf591e94ae71a27a13974559e72f7e9fde3ec174b26ba2e"},
+ {file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"},
+ {file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"},
]
[package.extras]
@@ -2641,18 +2807,18 @@ requests = ">=2.0,<3.0"
[[package]]
name = "zipp"
-version = "3.11.0"
+version = "3.12.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
- {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"},
- {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"},
+ {file = "zipp-3.12.0-py3-none-any.whl", hash = "sha256:9eb0a4c5feab9b08871db0d672745b53450d7f26992fd1e4653aa43345e97b86"},
+ {file = "zipp-3.12.0.tar.gz", hash = "sha256:73efd63936398aac78fd92b6f4865190119d6c91b531532e798977ea8dd402eb"},
]
[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
[extras]
@@ -2665,4 +2831,4 @@ validation = ["fastjsonschema"]
[metadata]
lock-version = "2.0"
python-versions = "^3.7.4"
-content-hash = "5b925c7de2441a1193ae75efe1548070b10b71cb99bc4627e5cabef683b05f95"
+content-hash = "b897ddb6a5d83dd5acce3c612c912af40b6c6c7821abc4804a93037e2f26639b"
diff --git a/pyproject.toml b/pyproject.toml
index 29e6aa21609..da3333be635 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,13 +1,13 @@
[tool.poetry]
name = "aws_lambda_powertools"
-version = "2.7.0"
+version = "2.7.1"
description = "A suite of utilities for AWS Lambda functions to ease adopting best practices such as tracing, structured logging, custom metrics, batching, idempotency, feature flags, and more."
authors = ["Amazon Web Services"]
include = ["aws_lambda_powertools/py.typed", "THIRD-PARTY-LICENSES"]
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
+ "License :: OSI Approved :: MIT No Attribution License (MIT-0)",
"Natural Language :: English",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
@@ -16,7 +16,9 @@ classifiers=[
repository="https://github.com/awslabs/aws-lambda-powertools-python"
readme = "README.md"
keywords = ["aws_lambda_powertools", "aws", "tracing", "logging", "lambda", "powertools", "feature_flags", "idempotency", "middleware"]
-license = "MIT-0"
+# MIT-0 is not recognized as an existing license from poetry.
+# By using `MIT` as a license value, a `License :: OSI Approved :: MIT License` classifier is added to the classifiers list.
+license = "MIT"
[tool.poetry.dependencies]
python = "^3.7.4"
@@ -27,7 +29,7 @@ boto3 = { version = "^1.20.32", optional = true }
typing-extensions = "^4.4.0"
[tool.poetry.dev-dependencies]
-coverage = {extras = ["toml"], version = "^7.0"}
+coverage = {extras = ["toml"], version = "^7.1"}
pytest = "^7.2.1"
black = "^22.12"
boto3 = "^1.18"
@@ -42,7 +44,7 @@ flake8-debugger = "^4.0.0"
flake8-fixme = "^1.1.1"
flake8-variables-names = "^0.0.5"
flake8-black = "^0.3.6"
-isort = "^5.11.4"
+isort = "^5.11.5"
pytest-cov = "^4.0.0"
pytest-mock = "^3.5.1"
pdoc3 = "^0.10.0"
@@ -51,35 +53,38 @@ bandit = "^1.7.1"
radon = "^5.1.0"
xenon = "^0.9.0"
flake8-eradicate = "^1.2.1"
-flake8-bugbear = "^22.12.6"
+flake8-bugbear = "^23.1.20"
mkdocs-git-revision-date-plugin = "^0.3.2"
mike = "^1.1.2"
retry = "^0.9.2"
pytest-xdist = "^3.1.0"
-aws-cdk-lib = "^2.61.1"
+aws-cdk-lib = "^2.62.2"
"aws-cdk.aws-apigatewayv2-alpha" = "^2.38.1-alpha.0"
"aws-cdk.aws-apigatewayv2-integrations-alpha" = "^2.38.1-alpha.0"
+"aws-cdk.aws-apigatewayv2-authorizers-alpha" = "^2.38.1-alpha.0"
pytest-benchmark = "^4.0.0"
python-snappy = "^0.6.1"
mypy-boto3-appconfig = "^1.26.0"
-mypy-boto3-cloudformation = "^1.26.35"
+mypy-boto3-cloudformation = "^1.26.57"
mypy-boto3-cloudwatch = "^1.26.52"
mypy-boto3-dynamodb = "^1.26.24"
-mypy-boto3-lambda = "^1.26.49"
+mypy-boto3-lambda = "^1.26.55"
mypy-boto3-logs = "^1.26.53"
mypy-boto3-secretsmanager = "^1.26.49"
mypy-boto3-ssm = "^1.26.43"
-mypy-boto3-s3 = "^1.26.0"
+mypy-boto3-s3 = "^1.26.58"
mypy-boto3-xray = "^1.26.11"
types-requests = "^2.28.11"
typing-extensions = "^4.4.0"
-mkdocs-material = "^9.0.6"
+mkdocs-material = "^9.0.8"
filelock = "^3.9.0"
checksumdir = "^1.2.0"
mypy-boto3-appconfigdata = "^1.26.0"
importlib-metadata = "^6.0"
ijson = "^3.2.0"
typed-ast = { version = "^1.5.4", python = "< 3.8"}
+hvac = "^1.0.2"
+aws-requests-auth = "^0.4.3"
[tool.poetry.extras]
parser = ["pydantic"]
diff --git a/tests/e2e/event_handler/conftest.py b/tests/e2e/event_handler/conftest.py
index 43941946ac7..664c870e1de 100644
--- a/tests/e2e/event_handler/conftest.py
+++ b/tests/e2e/event_handler/conftest.py
@@ -3,7 +3,7 @@
from tests.e2e.event_handler.infrastructure import EventHandlerStack
-@pytest.fixture(autouse=True, scope="module")
+@pytest.fixture(autouse=True, scope="package")
def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
diff --git a/tests/e2e/event_handler/infrastructure.py b/tests/e2e/event_handler/infrastructure.py
index da456038a25..ca0d1ad8378 100644
--- a/tests/e2e/event_handler/infrastructure.py
+++ b/tests/e2e/event_handler/infrastructure.py
@@ -3,6 +3,7 @@
from aws_cdk import CfnOutput
from aws_cdk import aws_apigateway as apigwv1
from aws_cdk import aws_apigatewayv2_alpha as apigwv2
+from aws_cdk import aws_apigatewayv2_authorizers_alpha as apigwv2authorizers
from aws_cdk import aws_apigatewayv2_integrations_alpha as apigwv2integrations
from aws_cdk import aws_ec2 as ec2
from aws_cdk import aws_elasticloadbalancingv2 as elbv2
@@ -57,7 +58,12 @@ def _create_alb_listener(
CfnOutput(self.stack, f"ALB{name}ListenerPort", value=str(port))
def _create_api_gateway_http(self, function: Function):
- apigw = apigwv2.HttpApi(self.stack, "APIGatewayHTTP", create_default_stage=True)
+ apigw = apigwv2.HttpApi(
+ self.stack,
+ "APIGatewayHTTP",
+ create_default_stage=True,
+ default_authorizer=apigwv2authorizers.HttpIamAuthorizer(),
+ )
apigw.add_routes(
path="/todos",
methods=[apigwv2.HttpMethod.POST],
@@ -76,5 +82,5 @@ def _create_api_gateway_rest(self, function: Function):
def _create_lambda_function_url(self, function: Function):
# Maintenance: move auth to IAM when we create sigv4 builders
- function_url = function.add_function_url(auth_type=FunctionUrlAuthType.NONE)
+ function_url = function.add_function_url(auth_type=FunctionUrlAuthType.AWS_IAM)
CfnOutput(self.stack, "LambdaFunctionUrl", value=function_url.url)
diff --git a/tests/e2e/event_handler/test_header_serializer.py b/tests/e2e/event_handler/test_header_serializer.py
index eedb69ccaad..a1ce643d993 100644
--- a/tests/e2e/event_handler/test_header_serializer.py
+++ b/tests/e2e/event_handler/test_header_serializer.py
@@ -5,6 +5,7 @@
from aws_lambda_powertools.shared.cookies import Cookie
from tests.e2e.utils import data_fetcher
+from tests.e2e.utils.auth import build_iam_auth
@pytest.fixture
@@ -36,6 +37,7 @@ def lambda_function_url_endpoint(infrastructure: dict) -> str:
return infrastructure.get("LambdaFunctionUrl", "")
+@pytest.mark.xdist_group(name="event_handler")
def test_alb_headers_serializer(alb_basic_listener_endpoint):
# GIVEN
url = f"{alb_basic_listener_endpoint}/todos"
@@ -74,6 +76,7 @@ def test_alb_headers_serializer(alb_basic_listener_endpoint):
assert response.cookies.get(last_cookie.name) == last_cookie.value
+@pytest.mark.xdist_group(name="event_handler")
def test_alb_multi_value_headers_serializer(alb_multi_value_header_listener_endpoint):
# GIVEN
url = f"{alb_multi_value_header_listener_endpoint}/todos"
@@ -112,6 +115,7 @@ def test_alb_multi_value_headers_serializer(alb_multi_value_header_listener_endp
assert response.cookies.get(cookie.name) == cookie.value
+@pytest.mark.xdist_group(name="event_handler")
def test_api_gateway_rest_headers_serializer(apigw_rest_endpoint):
# GIVEN
url = f"{apigw_rest_endpoint}todos"
@@ -147,6 +151,7 @@ def test_api_gateway_rest_headers_serializer(apigw_rest_endpoint):
assert response.cookies.get(cookie.name) == cookie.value
+@pytest.mark.xdist_group(name="event_handler")
def test_api_gateway_http_headers_serializer(apigw_http_endpoint):
# GIVEN
url = f"{apigw_http_endpoint}todos"
@@ -164,6 +169,7 @@ def test_api_gateway_http_headers_serializer(apigw_http_endpoint):
method="POST",
url=url,
json={"body": body, "status_code": status_code, "headers": headers, "cookies": list(map(str, cookies))},
+ auth=build_iam_auth(url=url, aws_service="execute-api"),
)
)
@@ -182,6 +188,7 @@ def test_api_gateway_http_headers_serializer(apigw_http_endpoint):
assert response.cookies.get(cookie.name) == cookie.value
+@pytest.mark.xdist_group(name="event_handler")
def test_lambda_function_url_headers_serializer(lambda_function_url_endpoint):
# GIVEN
url = f"{lambda_function_url_endpoint}todos" # the function url endpoint already has the trailing /
@@ -199,6 +206,7 @@ def test_lambda_function_url_headers_serializer(lambda_function_url_endpoint):
method="POST",
url=url,
json={"body": body, "status_code": status_code, "headers": headers, "cookies": list(map(str, cookies))},
+ auth=build_iam_auth(url=url, aws_service="lambda"),
)
)
diff --git a/tests/e2e/event_handler/test_paths_ending_with_slash.py b/tests/e2e/event_handler/test_paths_ending_with_slash.py
index 4c1461d6fc5..d871edbb98e 100644
--- a/tests/e2e/event_handler/test_paths_ending_with_slash.py
+++ b/tests/e2e/event_handler/test_paths_ending_with_slash.py
@@ -2,6 +2,7 @@
from requests import HTTPError, Request
from tests.e2e.utils import data_fetcher
+from tests.e2e.utils.auth import build_iam_auth
@pytest.fixture
@@ -33,6 +34,7 @@ def lambda_function_url_endpoint(infrastructure: dict) -> str:
return infrastructure.get("LambdaFunctionUrl", "")
+@pytest.mark.xdist_group(name="event_handler")
def test_api_gateway_rest_trailing_slash(apigw_rest_endpoint):
# GIVEN API URL ends in a trailing slash
url = f"{apigw_rest_endpoint}todos/"
@@ -44,6 +46,7 @@ def test_api_gateway_rest_trailing_slash(apigw_rest_endpoint):
method="POST",
url=url,
json={"body": body},
+ auth=build_iam_auth(url=url, aws_service="lambda"),
)
)
@@ -51,6 +54,7 @@ def test_api_gateway_rest_trailing_slash(apigw_rest_endpoint):
assert response.status_code == 200
+@pytest.mark.xdist_group(name="event_handler")
def test_api_gateway_http_trailing_slash(apigw_http_endpoint):
# GIVEN the URL for the API ends in a trailing slash API gateway should return a 404
url = f"{apigw_http_endpoint}todos/"
@@ -63,10 +67,12 @@ def test_api_gateway_http_trailing_slash(apigw_http_endpoint):
method="POST",
url=url,
json={"body": body},
+ auth=build_iam_auth(url=url, aws_service="lambda"),
)
)
+@pytest.mark.xdist_group(name="event_handler")
def test_lambda_function_url_trailing_slash(lambda_function_url_endpoint):
# GIVEN the URL for the API ends in a trailing slash it should behave as if there was not one
url = f"{lambda_function_url_endpoint}todos/" # the function url endpoint already has the trailing /
@@ -79,10 +85,12 @@ def test_lambda_function_url_trailing_slash(lambda_function_url_endpoint):
method="POST",
url=url,
json={"body": body},
+ auth=build_iam_auth(url=url, aws_service="lambda"),
)
)
+@pytest.mark.xdist_group(name="event_handler")
def test_alb_url_trailing_slash(alb_multi_value_header_listener_endpoint):
# GIVEN url has a trailing slash - it should behave as if there was not one
url = f"{alb_multi_value_header_listener_endpoint}/todos/"
@@ -95,5 +103,6 @@ def test_alb_url_trailing_slash(alb_multi_value_header_listener_endpoint):
method="POST",
url=url,
json={"body": body},
+ auth=build_iam_auth(url=url, aws_service="lambda"),
)
)
diff --git a/tests/e2e/idempotency/conftest.py b/tests/e2e/idempotency/conftest.py
index 24a7c71c1f2..61578d904a6 100644
--- a/tests/e2e/idempotency/conftest.py
+++ b/tests/e2e/idempotency/conftest.py
@@ -3,8 +3,8 @@
from tests.e2e.idempotency.infrastructure import IdempotencyDynamoDBStack
-@pytest.fixture(autouse=True, scope="module")
-def infrastructure(tmp_path_factory, worker_id):
+@pytest.fixture(autouse=True, scope="package")
+def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
Yields
diff --git a/tests/e2e/idempotency/test_idempotency_dynamodb.py b/tests/e2e/idempotency/test_idempotency_dynamodb.py
index 87b61d285ec..d3452a1a161 100644
--- a/tests/e2e/idempotency/test_idempotency_dynamodb.py
+++ b/tests/e2e/idempotency/test_idempotency_dynamodb.py
@@ -27,6 +27,7 @@ def idempotency_table_name(infrastructure: dict) -> str:
return infrastructure.get("DynamoDBTable", "")
+@pytest.mark.xdist_group(name="idempotency")
def test_ttl_caching_expiration_idempotency(ttl_cache_expiration_handler_fn_arn: str):
# GIVEN
payload = json.dumps({"message": "Lambda Powertools - TTL 5s"})
@@ -56,6 +57,7 @@ def test_ttl_caching_expiration_idempotency(ttl_cache_expiration_handler_fn_arn:
assert third_execution_response != second_execution_response
+@pytest.mark.xdist_group(name="idempotency")
def test_ttl_caching_timeout_idempotency(ttl_cache_timeout_handler_fn_arn: str):
# GIVEN
payload_timeout_execution = json.dumps({"sleep": 5, "message": "Lambda Powertools - TTL 1s"})
@@ -79,6 +81,7 @@ def test_ttl_caching_timeout_idempotency(ttl_cache_timeout_handler_fn_arn: str):
assert payload_working_execution == execution_working_response
+@pytest.mark.xdist_group(name="idempotency")
def test_parallel_execution_idempotency(parallel_execution_handler_fn_arn: str):
# GIVEN
arguments = json.dumps({"message": "Lambda Powertools - Parallel execution"})
diff --git a/tests/e2e/logger/conftest.py b/tests/e2e/logger/conftest.py
index a31be77031b..ad336931a93 100644
--- a/tests/e2e/logger/conftest.py
+++ b/tests/e2e/logger/conftest.py
@@ -3,8 +3,8 @@
from tests.e2e.logger.infrastructure import LoggerStack
-@pytest.fixture(autouse=True, scope="module")
-def infrastructure(tmp_path_factory, worker_id):
+@pytest.fixture(autouse=True, scope="package")
+def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
Yields
diff --git a/tests/e2e/logger/test_logger.py b/tests/e2e/logger/test_logger.py
index e5c27dd0a8f..80379125d11 100644
--- a/tests/e2e/logger/test_logger.py
+++ b/tests/e2e/logger/test_logger.py
@@ -17,6 +17,7 @@ def basic_handler_fn_arn(infrastructure: dict) -> str:
return infrastructure.get("BasicHandlerArn", "")
+@pytest.mark.xdist_group(name="logger")
def test_basic_lambda_logs_visible(basic_handler_fn, basic_handler_fn_arn):
# GIVEN
message = "logs should be visible with default settings"
@@ -29,7 +30,7 @@ def test_basic_lambda_logs_visible(basic_handler_fn, basic_handler_fn_arn):
data_fetcher.get_lambda_response(lambda_arn=basic_handler_fn_arn, payload=payload)
# THEN
- logs = data_fetcher.get_logs(function_name=basic_handler_fn, start_time=execution_time)
+ logs = data_fetcher.get_logs(function_name=basic_handler_fn, start_time=execution_time, minimum_log_entries=2)
assert len(logs) == 2
assert len(logs.get_cold_start_log()) == 1
diff --git a/tests/e2e/metrics/conftest.py b/tests/e2e/metrics/conftest.py
index 2f72e7950be..197aaff847f 100644
--- a/tests/e2e/metrics/conftest.py
+++ b/tests/e2e/metrics/conftest.py
@@ -3,8 +3,8 @@
from tests.e2e.metrics.infrastructure import MetricsStack
-@pytest.fixture(autouse=True, scope="module")
-def infrastructure(tmp_path_factory, worker_id):
+@pytest.fixture(autouse=True, scope="package")
+def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
Yields
diff --git a/tests/e2e/metrics/test_metrics.py b/tests/e2e/metrics/test_metrics.py
index 516f93ac1f0..192cbcc25af 100644
--- a/tests/e2e/metrics/test_metrics.py
+++ b/tests/e2e/metrics/test_metrics.py
@@ -28,6 +28,7 @@ def cold_start_fn_arn(infrastructure: dict) -> str:
METRIC_NAMESPACE = "powertools-e2e-metric"
+@pytest.mark.xdist_group(name="metrics")
def test_basic_lambda_metric_is_visible(basic_handler_fn: str, basic_handler_fn_arn: str):
# GIVEN
metric_name = data_builder.build_metric_name()
@@ -47,6 +48,7 @@ def test_basic_lambda_metric_is_visible(basic_handler_fn: str, basic_handler_fn_
assert metric_values == [3.0]
+@pytest.mark.xdist_group(name="metrics")
def test_cold_start_metric(cold_start_fn_arn: str, cold_start_fn: str):
# GIVEN
metric_name = "ColdStart"
diff --git a/tests/e2e/parameters/conftest.py b/tests/e2e/parameters/conftest.py
index f4c9d7396dd..99146607384 100644
--- a/tests/e2e/parameters/conftest.py
+++ b/tests/e2e/parameters/conftest.py
@@ -3,8 +3,8 @@
from tests.e2e.parameters.infrastructure import ParametersStack
-@pytest.fixture(autouse=True, scope="module")
-def infrastructure(tmp_path_factory, worker_id):
+@pytest.fixture(autouse=True, scope="package")
+def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
Yields
diff --git a/tests/e2e/parameters/infrastructure.py b/tests/e2e/parameters/infrastructure.py
index e2cd5101ba7..018fceab2aa 100644
--- a/tests/e2e/parameters/infrastructure.py
+++ b/tests/e2e/parameters/infrastructure.py
@@ -27,7 +27,7 @@ def create_resources(self):
iam.PolicyStatement(
effect=iam.Effect.ALLOW,
actions=[
- "ssm:GetParameter",
+ "ssm:GetParameters",
],
resources=[f"arn:aws:ssm:{self.region}:{self.account_id}:parameter/powertools/e2e/parameters/*"],
)
diff --git a/tests/e2e/parameters/test_appconfig.py b/tests/e2e/parameters/test_appconfig.py
index 0129adb1515..7cf6f87067f 100644
--- a/tests/e2e/parameters/test_appconfig.py
+++ b/tests/e2e/parameters/test_appconfig.py
@@ -35,6 +35,7 @@ def parameter_appconfig_freeform_profile(infrastructure: dict) -> str:
return infrastructure.get("AppConfigProfile", "")
+@pytest.mark.xdist_group(name="parameters")
def test_get_parameter_appconfig_freeform(
parameter_appconfig_freeform_handler_fn_arn: str,
parameter_appconfig_freeform_value: str,
diff --git a/tests/e2e/parameters/test_ssm.py b/tests/e2e/parameters/test_ssm.py
index 7e9614f8ea0..239813fab51 100644
--- a/tests/e2e/parameters/test_ssm.py
+++ b/tests/e2e/parameters/test_ssm.py
@@ -17,7 +17,7 @@ def parameters_list(infrastructure: dict) -> List[str]:
return json.loads(param_list)
-#
+@pytest.mark.xdist_group(name="parameters")
def test_get_parameters_by_name(
ssm_get_parameters_by_name_fn_arn: str,
parameters_list: str,
diff --git a/tests/e2e/pytest.ini b/tests/e2e/pytest.ini
new file mode 100644
index 00000000000..3fc35fa5847
--- /dev/null
+++ b/tests/e2e/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = -ra -vv --dist loadgroup
\ No newline at end of file
diff --git a/tests/e2e/streaming/conftest.py b/tests/e2e/streaming/conftest.py
index c3a44365d39..94f7f212af0 100644
--- a/tests/e2e/streaming/conftest.py
+++ b/tests/e2e/streaming/conftest.py
@@ -3,8 +3,8 @@
from tests.e2e.streaming.infrastructure import StreamingStack
-@pytest.fixture(autouse=True, scope="module")
-def infrastructure(tmp_path_factory, worker_id):
+@pytest.fixture(autouse=True, scope="package")
+def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
Yields
diff --git a/tests/e2e/streaming/test_s3_object.py b/tests/e2e/streaming/test_s3_object.py
index 1e2fe1a0222..fe4fd638b10 100644
--- a/tests/e2e/streaming/test_s3_object.py
+++ b/tests/e2e/streaming/test_s3_object.py
@@ -21,6 +21,7 @@ def s3_object_handler_fn_arn(infrastructure: dict) -> str:
return infrastructure.get("S3ObjectHandler", "")
+@pytest.mark.xdist_group(name="streaming")
def get_object_version(bucket, key) -> str:
s3 = boto3.client("s3")
versions = s3.list_object_versions(Bucket=bucket)
@@ -43,6 +44,7 @@ def get_lambda_result_payload(s3_object_handler_fn_arn: str, payload: dict) -> d
return json.loads(handler_result["Payload"].read())
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_size(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "plain.txt"}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
@@ -50,6 +52,7 @@ def test_s3_object_size(s3_object_handler_fn_arn, regular_bucket_name):
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_versioned_object_size(s3_object_handler_fn_arn, versioned_bucket_name):
key = "plain.txt"
payload = {
@@ -62,18 +65,21 @@ def test_s3_versioned_object_size(s3_object_handler_fn_arn, versioned_bucket_nam
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_non_existent(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "NOTEXISTENT.txt"}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("error") == "Not found"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_csv_constructor(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "csv.txt", "is_csv": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_versioned_object_csv_constructor(s3_object_handler_fn_arn, versioned_bucket_name):
key = "csv.txt"
payload = {
@@ -86,24 +92,28 @@ def test_s3_versioned_object_csv_constructor(s3_object_handler_fn_arn, versioned
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_csv_transform(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "csv.txt", "transform_csv": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_csv_transform_in_place(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "csv.txt", "transform_csv": True, "in_place": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_csv_gzip_constructor(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "csv.txt.gz", "is_csv": True, "is_gzip": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_versioned_object_csv_gzip_constructor(s3_object_handler_fn_arn, versioned_bucket_name):
key = "csv.txt.gz"
payload = {
@@ -117,12 +127,14 @@ def test_s3_versioned_object_csv_gzip_constructor(s3_object_handler_fn_arn, vers
assert result.get("body") == {"name": "hello", "value": "world"}
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_gzip_constructor(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "plain.txt.gz", "is_gzip": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_versioned_object_gzip_constructor(s3_object_handler_fn_arn, versioned_bucket_name):
key = "plain.txt.gz"
payload = {
@@ -135,18 +147,21 @@ def test_s3_versioned_object_gzip_constructor(s3_object_handler_fn_arn, versione
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_gzip_transform(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "plain.txt.gz", "transform_gzip": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_gzip_transform_in_place(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "plain.txt.gz", "transform_gzip": True, "in_place": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
assert result.get("body") == "hello world"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_zip_transform(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "fileset.zip", "transform_zip": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
@@ -154,6 +169,7 @@ def test_s3_object_zip_transform(s3_object_handler_fn_arn, regular_bucket_name):
assert result.get("body") == "This is file 2"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_zip_transform_in_place(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "fileset.zip", "transform_zip": True, "in_place": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
@@ -161,6 +177,7 @@ def test_s3_object_zip_transform_in_place(s3_object_handler_fn_arn, regular_buck
assert result.get("body") == "This is file 2"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_zip_lzma_transform(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "fileset.zip.lzma", "transform_zip_lzma": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
@@ -168,6 +185,7 @@ def test_s3_object_zip_lzma_transform(s3_object_handler_fn_arn, regular_bucket_n
assert result.get("body") == "This is file 2"
+@pytest.mark.xdist_group(name="streaming")
def test_s3_object_zip_lzma_transform_in_place(s3_object_handler_fn_arn, regular_bucket_name):
payload = {"bucket": regular_bucket_name, "key": "fileset.zip.lzma", "transform_zip_lzma": True, "in_place": True}
result = get_lambda_result_payload(s3_object_handler_fn_arn, payload)
diff --git a/tests/e2e/tracer/conftest.py b/tests/e2e/tracer/conftest.py
index afb34ffee2b..d3728ab91ba 100644
--- a/tests/e2e/tracer/conftest.py
+++ b/tests/e2e/tracer/conftest.py
@@ -3,7 +3,7 @@
from tests.e2e.tracer.infrastructure import TracerStack
-@pytest.fixture(autouse=True, scope="module")
+@pytest.fixture(autouse=True, scope="package")
def infrastructure():
"""Setup and teardown logic for E2E test infrastructure
diff --git a/tests/e2e/tracer/test_tracer.py b/tests/e2e/tracer/test_tracer.py
index e2abc5af6bc..5dfe68ee08c 100644
--- a/tests/e2e/tracer/test_tracer.py
+++ b/tests/e2e/tracer/test_tracer.py
@@ -36,6 +36,7 @@ def async_fn(infrastructure: dict) -> str:
return infrastructure.get("AsyncCapture", "")
+@pytest.mark.xdist_group(name="tracer")
def test_lambda_handler_trace_is_visible(basic_handler_fn_arn: str, basic_handler_fn: str):
# GIVEN
service = data_builder.build_service_name()
@@ -64,6 +65,7 @@ def test_lambda_handler_trace_is_visible(basic_handler_fn_arn: str, basic_handle
assert len(trace.get_subsegment(name=method_subsegment)) == 2
+@pytest.mark.xdist_group(name="tracer")
def test_lambda_handler_trace_multiple_functions_same_name(same_function_name_arn: str, same_function_name_fn: str):
# GIVEN
service = data_builder.build_service_name()
@@ -90,6 +92,7 @@ def test_lambda_handler_trace_multiple_functions_same_name(same_function_name_ar
assert len(trace.get_subsegment(name=method_subsegment_comments)) == 1
+@pytest.mark.xdist_group(name="tracer")
def test_async_trace_is_visible(async_fn_arn: str, async_fn: str):
# GIVEN
service = data_builder.build_service_name()
diff --git a/tests/e2e/utils/auth.py b/tests/e2e/utils/auth.py
new file mode 100644
index 00000000000..8f50bfb9aef
--- /dev/null
+++ b/tests/e2e/utils/auth.py
@@ -0,0 +1,13 @@
+from urllib.parse import urlparse
+
+import boto3
+from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
+
+
+def build_iam_auth(url: str, aws_service: str) -> BotoAWSRequestsAuth:
+ """Generates IAM auth keys for a given hostname and service.
+ This can be directly passed on to the requests library to authenticate the request.
+ """
+ hostname = urlparse(url).hostname
+ region = boto3.Session().region_name
+ return BotoAWSRequestsAuth(aws_host=hostname, aws_region=region, aws_service=aws_service)
diff --git a/tests/e2e/utils/data_fetcher/logs.py b/tests/e2e/utils/data_fetcher/logs.py
index a005009f5f5..79fcee9290b 100644
--- a/tests/e2e/utils/data_fetcher/logs.py
+++ b/tests/e2e/utils/data_fetcher/logs.py
@@ -29,6 +29,7 @@ def __init__(
start_time: datetime,
log_client: Optional[CloudWatchLogsClient] = None,
filter_expression: Optional[str] = None,
+ minimum_log_entries: int = 1,
):
"""Fetch and expose Powertools Logger logs from CloudWatch Logs
@@ -42,12 +43,15 @@ def __init__(
Amazon CloudWatch Logs Client, by default boto3.client('logs)
filter_expression : Optional[str], optional
CloudWatch Logs Filter Pattern expression, by default "message"
+ minimum_log_entries: int
+ Minimum number of log entries to be retrieved before exhausting retry attempts
"""
self.function_name = function_name
self.start_time = int(start_time.timestamp())
self.log_client = log_client or boto3.client("logs")
self.filter_expression = filter_expression or "message" # Logger message key
self.log_group = f"/aws/lambda/{self.function_name}"
+ self.minimum_log_entries = minimum_log_entries
self.logs: List[Log] = self._get_logs()
def get_log(self, key: str, value: Optional[any] = None) -> List[Log]:
@@ -112,6 +116,11 @@ def _get_logs(self) -> List[Log]:
continue
filtered_logs.append(message)
+ if len(filtered_logs) < self.minimum_log_entries:
+ raise ValueError(
+ f"Number of log entries found doesn't meet minimum required ({self.minimum_log_entries}). Repeating..."
+ )
+
return filtered_logs
def __len__(self) -> int:
@@ -122,6 +131,7 @@ def __len__(self) -> int:
def get_logs(
function_name: str,
start_time: datetime,
+ minimum_log_entries: int = 1,
filter_expression: Optional[str] = None,
log_client: Optional[CloudWatchLogsClient] = None,
) -> LogFetcher:
@@ -133,6 +143,8 @@ def get_logs(
Name of Lambda function to fetch logs for
start_time : datetime
Start date range to filter traces
+ minimum_log_entries : int
+ Minimum number of log entries to be retrieved before exhausting retry attempts
log_client : Optional[CloudWatchLogsClient], optional
Amazon CloudWatch Logs Client, by default boto3.client('logs)
filter_expression : Optional[str], optional
@@ -144,5 +156,9 @@ def get_logs(
LogFetcher instance with logs available as properties and methods
"""
return LogFetcher(
- function_name=function_name, start_time=start_time, filter_expression=filter_expression, log_client=log_client
+ function_name=function_name,
+ start_time=start_time,
+ filter_expression=filter_expression,
+ log_client=log_client,
+ minimum_log_entries=minimum_log_entries,
)
diff --git a/tests/e2e/utils/functions.py b/tests/e2e/utils/functions.py
index 7b64c439298..db70f4ab6b9 100644
--- a/tests/e2e/utils/functions.py
+++ b/tests/e2e/utils/functions.py
@@ -1,4 +1,6 @@
-from concurrent.futures import ThreadPoolExecutor
+import time
+from concurrent.futures import Future, ThreadPoolExecutor
+from typing import List
from tests.e2e.utils import data_fetcher # noqa F401
@@ -6,9 +8,25 @@
def execute_lambdas_in_parallel(function_name: str, lambdas_arn: list, arguments: str):
result_list = []
with ThreadPoolExecutor() as executor:
- running_tasks = executor.map(lambda exec: eval(function_name)(*exec), [(arn, arguments) for arn in lambdas_arn])
+ running_tasks: List[Future] = []
+ for arn in lambdas_arn:
+ # Sleep 0.5, 1, 1.5, ... seconds between each invocation. This way
+ # we can guarantee that lambdas are executed in parallel, but they are
+ # called in the same "order" as they are passed in, thus guaranteeing that
+ # we can assert on the correct output.
+ time.sleep(0.5 * len(running_tasks))
+ running_tasks.append(
+ executor.submit(
+ lambda lname, larn, largs: eval(lname)(larn, largs),
+ function_name,
+ arn,
+ arguments,
+ )
+ )
+
executor.shutdown(wait=True)
+
for running_task in running_tasks:
- result_list.append(running_task)
+ result_list.append(running_task.result())
return result_list
diff --git a/tests/functional/idempotency/test_idempotency.py b/tests/functional/idempotency/test_idempotency.py
index 8d78c1bdf2b..e3131747e48 100644
--- a/tests/functional/idempotency/test_idempotency.py
+++ b/tests/functional/idempotency/test_idempotency.py
@@ -397,7 +397,7 @@ def test_idempotent_lambda_exception(
def lambda_handler(event, context):
raise Exception("Something went wrong!")
- with pytest.raises(Exception):
+ with pytest.raises(Exception, match="Something went wrong!"):
lambda_handler(lambda_apigw_event, lambda_context)
stubber.assert_no_pending_responses()