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/poetry.lock b/poetry.lock index b06738c5b3a..ee2d038ae92 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,57 +55,57 @@ 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.53.0,<3.0.0" +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" @@ -131,23 +132,25 @@ typeguard = ">=2.13.3,<2.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 +230,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 +250,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 +266,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 +321,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,18 +459,18 @@ 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" @@ -481,14 +567,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] @@ -766,6 +852,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,16 +989,35 @@ 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]] @@ -966,14 +1087,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 +1122,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 +1137,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 +1154,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" @@ -1062,7 +1184,6 @@ category = "dev" optional = false python-versions = "*" files = [ - {file = "junit-xml-1.9.tar.gz", hash = "sha256:de16a051990d4e25a3982b2dd9e89d671067548718866416faec14d9de56db9f"}, {file = "junit_xml-1.9-py2.py3-none-any.whl", hash = "sha256:ec5ca1a55aefdd76d28fcc0b135251d156c7106fa979686a4b48d62b761b4732"}, ] @@ -1128,52 +1249,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]] @@ -1282,14 +1413,14 @@ mkdocs = ">=0.17" [[package]] name = "mkdocs-material" -version = "9.0.8" +version = "9.0.9" description = "Documentation that simply works" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material-9.0.8-py3-none-any.whl", hash = "sha256:03f8a2249627efb91a57d9f4a4e298d2d61d6e65fe2a864cc5961dc540bdd540"}, - {file = "mkdocs_material-9.0.8.tar.gz", hash = "sha256:268e7aab0b8585352400b4e93bfe4efd0ca213005d7bae1a0ec69b7ded205fcd"}, + {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] @@ -1392,14 +1523,14 @@ typing-extensions = ">=4.1.0" [[package]] name = "mypy-boto3-cloudformation" -version = "1.26.57" -description = "Type annotations for boto3.CloudFormation 1.26.57 service generated with mypy-boto3-builder 7.12.3" +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.57.tar.gz", hash = "sha256:c1659cf032825293b3eef1acca1a29fb82a7149b6c3ce06bbf405f54b78d3172"}, - {file = "mypy_boto3_cloudformation-1.26.57-py3-none-any.whl", hash = "sha256:4a45872b0fc1d503fa1147560fd842d3bcbec38aad4ca3516b51c33e6dfa05f2"}, + {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] @@ -1558,41 +1689,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]] @@ -1611,21 +1739,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" @@ -1711,7 +1854,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"}, @@ -1799,65 +1942,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]] @@ -2239,19 +2383,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" @@ -2309,23 +2453,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" @@ -2481,14 +2608,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] @@ -2513,37 +2640,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] @@ -2642,18 +2772,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] @@ -2666,4 +2796,4 @@ validation = ["fastjsonschema"] [metadata] lock-version = "2.0" python-versions = "^3.7.4" -content-hash = "56cd214c7cf052567ee4dc5829d2801b57dc8b484e185ccccac149275695619e" +content-hash = "3a1013eb7ad5ff7a4a1bcf3be36eda55135bae69aae74cd91c1fde062805e154" diff --git a/pyproject.toml b/pyproject.toml index e9aed57ce76..04c5255c81e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ 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" [tool.poetry.extras] parser = ["pydantic"]