From d878e7fbca132dd3f344c6d8d9886c18371d6ff2 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Sat, 27 Aug 2022 23:18:59 +0100 Subject: [PATCH 01/12] feat(capture_method): add module and qualname in tracer method name --- aws_lambda_powertools/tracing/tracer.py | 2 +- tests/unit/test_tracing.py | 54 +++++++++++++++++++------ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/aws_lambda_powertools/tracing/tracer.py b/aws_lambda_powertools/tracing/tracer.py index 8d9ad16a3d0..25f5ca17c3d 100644 --- a/aws_lambda_powertools/tracing/tracer.py +++ b/aws_lambda_powertools/tracing/tracer.py @@ -508,7 +508,7 @@ async def async_tasks(): functools.partial(self.capture_method, capture_response=capture_response, capture_error=capture_error), ) - method_name = f"{method.__name__}" + method_name = f"{method.__module__}.{method.__qualname__}" capture_response = resolve_truthy_env_var_choice( env=os.getenv(constants.TRACER_CAPTURE_RESPONSE_ENV, "true"), choice=capture_response diff --git a/tests/unit/test_tracing.py b/tests/unit/test_tracing.py index 2482b0177d3..f5da9c3d644 100644 --- a/tests/unit/test_tracing.py +++ b/tests/unit/test_tracing.py @@ -123,9 +123,11 @@ def greeting(name, message): # and add its response as trace metadata # and use service name as a metadata namespace assert in_subsegment_mock.in_subsegment.call_count == 1 - assert in_subsegment_mock.in_subsegment.call_args == mocker.call(name="## greeting") + assert in_subsegment_mock.in_subsegment.call_args == mocker.call( + name="## unit.test_tracing.test_tracer_method..greeting" + ) assert in_subsegment_mock.put_metadata.call_args == mocker.call( - key="greeting response", value=dummy_response, namespace="booking" + key="unit.test_tracing.test_tracer_method..greeting response", value=dummy_response, namespace="booking" ) @@ -251,7 +253,10 @@ def greeting(name, message): # THEN we should add the exception using method name as key plus error # and their service name as the namespace put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] - assert put_metadata_mock_args["key"] == "greeting error" + assert ( + put_metadata_mock_args["key"] + == "unit.test_tracing.test_tracer_method_exception_metadata..greeting error" + ) assert put_metadata_mock_args["namespace"] == "booking" @@ -303,15 +308,23 @@ async def greeting(name, message): # THEN we should add metadata for each response like we would for a sync decorated method assert in_subsegment_mock.in_subsegment.call_count == 2 - assert in_subsegment_greeting_call_args == mocker.call(name="## greeting") - assert in_subsegment_greeting2_call_args == mocker.call(name="## greeting_2") + assert in_subsegment_greeting_call_args == mocker.call( + name="## unit.test_tracing.test_tracer_method_nested_async..greeting" + ) + assert in_subsegment_greeting2_call_args == mocker.call( + name="## unit.test_tracing.test_tracer_method_nested_async..greeting_2" + ) assert in_subsegment_mock.put_metadata.call_count == 2 assert put_metadata_greeting2_call_args == mocker.call( - key="greeting_2 response", value=dummy_response, namespace="booking" + key="unit.test_tracing.test_tracer_method_nested_async..greeting_2 response", + value=dummy_response, + namespace="booking", ) assert put_metadata_greeting_call_args == mocker.call( - key="greeting response", value=dummy_response, namespace="booking" + key="unit.test_tracing.test_tracer_method_nested_async..greeting response", + value=dummy_response, + namespace="booking", ) @@ -353,7 +366,10 @@ async def greeting(name, message): # THEN we should add the exception using method name as key plus error # and their service name as the namespace put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] - assert put_metadata_mock_args["key"] == "greeting error" + assert ( + put_metadata_mock_args["key"] + == "unit.test_tracing.test_tracer_method_exception_metadata_async..greeting error" + ) assert put_metadata_mock_args["namespace"] == "booking" @@ -385,7 +401,9 @@ def handler(event, context): assert "test result" in in_subsegment_mock.put_metadata.call_args[1]["value"] assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") - assert yield_function_trace == mocker.call(name="## yield_with_capture") + assert yield_function_trace == mocker.call( + name="## unit.test_tracing.test_tracer_yield_from_context_manager..yield_with_capture" + ) assert "test result" in result @@ -409,7 +427,10 @@ def yield_with_capture(): # THEN we should add the exception using method name as key plus error # and their service name as the namespace put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] - assert put_metadata_mock_args["key"] == "yield_with_capture error" + assert ( + put_metadata_mock_args["key"] + == "unit.test_tracing.test_tracer_yield_from_context_manager_exception_metadata..yield_with_capture error" # noqa E501 + ) assert isinstance(put_metadata_mock_args["value"], ValueError) assert put_metadata_mock_args["namespace"] == "booking" @@ -451,7 +472,9 @@ def handler(event, context): assert "test result" in in_subsegment_mock.put_metadata.call_args[1]["value"] assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") - assert yield_function_trace == mocker.call(name="## yield_with_capture") + assert yield_function_trace == mocker.call( + name="## unit.test_tracing.test_tracer_yield_from_nested_context_manager..yield_with_capture" + ) assert "test result" in result @@ -481,7 +504,9 @@ def handler(event, context): assert "test result" in in_subsegment_mock.put_metadata.call_args[1]["value"] assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") - assert generator_fn_trace == mocker.call(name="## generator_fn") + assert generator_fn_trace == mocker.call( + name="## unit.test_tracing.test_tracer_yield_from_generator..generator_fn" + ) assert "test result" in result @@ -504,7 +529,10 @@ def generator_fn(): # THEN we should add the exception using method name as key plus error # and their service name as the namespace put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] - assert put_metadata_mock_args["key"] == "generator_fn error" + assert ( + put_metadata_mock_args["key"] + == "unit.test_tracing.test_tracer_yield_from_generator_exception_metadata..generator_fn error" + ) assert put_metadata_mock_args["namespace"] == "booking" assert isinstance(put_metadata_mock_args["value"], ValueError) assert str(put_metadata_mock_args["value"]) == "test" From 1696228035b7037cd8ac5fca7d6a6c9be20b7bc1 Mon Sep 17 00:00:00 2001 From: Ruben Fonseca Date: Mon, 29 Aug 2022 17:56:24 +0200 Subject: [PATCH 02/12] feat(event_handler): improved support for headers and cookies in v2 (#1455) Co-authored-by: Heitor Lessa --- .gitignore | 3 + aws_lambda_powertools/__init__.py | 6 +- .../event_handler/api_gateway.py | 27 +- .../event_handler/appsync.py | 3 +- .../shared/headers_serializer.py | 111 +++ .../utilities/data_classes/alb_event.py | 13 + .../data_classes/api_gateway_proxy_event.py | 11 + .../utilities/data_classes/common.py | 5 + docs/core/event_handler/api_gateway.md | 11 +- docs/upgrade.md | 57 ++ .../src/binary_responses_output.json | 4 +- .../src/compressing_responses_output.json | 6 +- .../src/fine_grained_responses.py | 3 +- .../src/fine_grained_responses_output.json | 7 +- ...ting_started_rest_api_resolver_output.json | 4 +- .../src/setting_cors_output.json | 8 +- mkdocs.yml | 1 + poetry.lock | 892 ++++++++---------- pyproject.toml | 34 +- tests/e2e/event_handler/__init__.py | 0 tests/e2e/event_handler/conftest.py | 28 + .../e2e/event_handler/handlers/alb_handler.py | 18 + .../handlers/api_gateway_http_handler.py | 18 + .../handlers/api_gateway_rest_handler.py | 18 + .../handlers/lambda_function_url_handler.py | 18 + tests/e2e/event_handler/infrastructure.py | 81 ++ .../event_handler/test_header_serializer.py | 141 +++ tests/e2e/utils/data_fetcher/__init__.py | 2 +- tests/e2e/utils/data_fetcher/common.py | 12 + tests/e2e/utils/infrastructure.py | 19 +- tests/events/albMultiValueHeadersEvent.json | 35 + .../event_handler/test_api_gateway.py | 170 ++-- .../event_handler/test_lambda_function_url.py | 21 + tests/functional/test_headers_serializer.py | 147 +++ 34 files changed, 1310 insertions(+), 624 deletions(-) create mode 100644 aws_lambda_powertools/shared/headers_serializer.py create mode 100644 docs/upgrade.md create mode 100644 tests/e2e/event_handler/__init__.py create mode 100644 tests/e2e/event_handler/conftest.py create mode 100644 tests/e2e/event_handler/handlers/alb_handler.py create mode 100644 tests/e2e/event_handler/handlers/api_gateway_http_handler.py create mode 100644 tests/e2e/event_handler/handlers/api_gateway_rest_handler.py create mode 100644 tests/e2e/event_handler/handlers/lambda_function_url_handler.py create mode 100644 tests/e2e/event_handler/infrastructure.py create mode 100644 tests/e2e/event_handler/test_header_serializer.py create mode 100644 tests/events/albMultiValueHeadersEvent.json create mode 100644 tests/functional/test_headers_serializer.py diff --git a/.gitignore b/.gitignore index b776e1999c2..cc01240a405 100644 --- a/.gitignore +++ b/.gitignore @@ -305,5 +305,8 @@ site/ !404.html !docs/overrides/*.html +# CDK +.cdk + !.github/workflows/lib examples/**/sam/.aws-sam diff --git a/aws_lambda_powertools/__init__.py b/aws_lambda_powertools/__init__.py index 65b5eb86730..750ae92c4d1 100644 --- a/aws_lambda_powertools/__init__.py +++ b/aws_lambda_powertools/__init__.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -"""Top-level package for Lambda Python Powertools.""" - +from pathlib import Path +"""Top-level package for Lambda Python Powertools.""" from .logging import Logger # noqa: F401 from .metrics import Metrics, single_metric # noqa: F401 from .package_logger import set_package_logger_handler @@ -10,4 +10,6 @@ __author__ = """Amazon Web Services""" +PACKAGE_PATH = Path(__file__).parent + set_package_logger_handler() diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 903fc7e828f..11adcfc2ed6 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -32,7 +32,7 @@ _SAFE_URI = "-._~()'!*:@,;" # https://www.ietf.org/rfc/rfc3986.txt # API GW/ALB decode non-safe URI chars; we must support them too _UNSAFE_URI = "%<> \[\]{}|^" # noqa: W605 -_NAMED_GROUP_BOUNDARY_PATTERN = fr"(?P\1[{_SAFE_URI}{_UNSAFE_URI}\\w]+)" +_NAMED_GROUP_BOUNDARY_PATTERN = rf"(?P\1[{_SAFE_URI}{_UNSAFE_URI}\\w]+)" class ProxyEventType(Enum): @@ -124,10 +124,11 @@ def __init__( def to_dict(self) -> Dict[str, str]: """Builds the configured Access-Control http headers""" - headers = { + headers: Dict[str, str] = { "Access-Control-Allow-Origin": self.allow_origin, "Access-Control-Allow-Headers": ",".join(sorted(self.allow_headers)), } + if self.expose_headers: headers["Access-Control-Expose-Headers"] = ",".join(self.expose_headers) if self.max_age is not None: @@ -145,7 +146,8 @@ def __init__( status_code: int, content_type: Optional[str], body: Union[str, bytes, None], - headers: Optional[Dict] = None, + headers: Optional[Dict[str, Union[str, List[str]]]] = None, + cookies: Optional[List[str]] = None, ): """ @@ -158,13 +160,16 @@ def __init__( provided http headers body: Union[str, bytes, None] Optionally set the response body. Note: bytes body will be automatically base64 encoded - headers: dict - Optionally set specific http headers. Setting "Content-Type" hear would override the `content_type` value. + headers: dict[str, Union[str, List[str]]] + Optionally set specific http headers. Setting "Content-Type" here would override the `content_type` value. + cookies: list[str] + Optionally set cookies. """ self.status_code = status_code self.body = body self.base64_encoded = False - self.headers: Dict = headers or {} + self.headers: Dict[str, Union[str, List[str]]] = headers if headers else {} + self.cookies = cookies or [] if content_type: self.headers.setdefault("Content-Type", content_type) @@ -196,11 +201,12 @@ def _add_cors(self, cors: CORSConfig): def _add_cache_control(self, cache_control: str): """Set the specified cache control headers for 200 http responses. For non-200 `no-cache` is used.""" - self.response.headers["Cache-Control"] = cache_control if self.response.status_code == 200 else "no-cache" + cache_control = cache_control if self.response.status_code == 200 else "no-cache" + self.response.headers["Cache-Control"] = cache_control def _compress(self): """Compress the response body, but only if `Accept-Encoding` headers includes gzip.""" - self.response.headers["Content-Encoding"] = "gzip" + self.response.headers["Content-Encoding"].append("gzip") if isinstance(self.response.body, str): logger.debug("Converting string response to bytes before compressing it") self.response.body = bytes(self.response.body, "utf-8") @@ -226,11 +232,12 @@ def build(self, event: BaseProxyEvent, cors: Optional[CORSConfig] = None) -> Dic logger.debug("Encoding bytes response with base64") self.response.base64_encoded = True self.response.body = base64.b64encode(self.response.body).decode() + return { "statusCode": self.response.status_code, - "headers": self.response.headers, "body": self.response.body, "isBase64Encoded": self.response.base64_encoded, + **event.header_serializer().serialize(headers=self.response.headers, cookies=self.response.cookies), } @@ -596,7 +603,7 @@ def _path_starts_with(path: str, prefix: str): def _not_found(self, method: str) -> ResponseBuilder: """Called when no matching route was found and includes support for the cors preflight response""" - headers = {} + headers: Dict[str, Union[str, List[str]]] = {} if self._cors: logger.debug("CORS is enabled, updating headers.") headers.update(self._cors.to_dict()) diff --git a/aws_lambda_powertools/event_handler/appsync.py b/aws_lambda_powertools/event_handler/appsync.py index 896b303cd08..4ddc51cd102 100644 --- a/aws_lambda_powertools/event_handler/appsync.py +++ b/aws_lambda_powertools/event_handler/appsync.py @@ -1,5 +1,4 @@ import logging -from abc import ABC from typing import Any, Callable, Optional, Type, TypeVar from aws_lambda_powertools.utilities.data_classes import AppSyncResolverEvent @@ -10,7 +9,7 @@ AppSyncResolverEventT = TypeVar("AppSyncResolverEventT", bound=AppSyncResolverEvent) -class BaseRouter(ABC): +class BaseRouter: current_event: AppSyncResolverEventT # type: ignore[valid-type] lambda_context: LambdaContext diff --git a/aws_lambda_powertools/shared/headers_serializer.py b/aws_lambda_powertools/shared/headers_serializer.py new file mode 100644 index 00000000000..4db7effe81b --- /dev/null +++ b/aws_lambda_powertools/shared/headers_serializer.py @@ -0,0 +1,111 @@ +import warnings +from collections import defaultdict +from typing import Any, Dict, List, Union + + +class BaseHeadersSerializer: + """ + Helper class to correctly serialize headers and cookies for Amazon API Gateway, + ALB and Lambda Function URL response payload. + """ + + def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: + """ + Serializes headers and cookies according to the request type. + Returns a dict that can be merged with the response payload. + + Parameters + ---------- + headers: Dict[str, List[str]] + A dictionary of headers to set in the response + cookies: List[str] + A list of cookies to set in the response + """ + raise NotImplementedError() + + +class HttpApiHeadersSerializer(BaseHeadersSerializer): + def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: + """ + When using HTTP APIs or LambdaFunctionURLs, everything is taken care automatically for us. + We can directly assign a list of cookies and a dict of headers to the response payload, and the + runtime will automatically serialize them correctly on the output. + + https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format + https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response + """ + + # Format 2.0 doesn't have multiValueHeaders or multiValueQueryStringParameters fields. + # Duplicate headers are combined with commas and included in the headers field. + combined_headers: Dict[str, str] = {} + for key, values in headers.items(): + if isinstance(values, str): + combined_headers[key] = values + else: + combined_headers[key] = ", ".join(values) + + return {"headers": combined_headers, "cookies": cookies} + + +class MultiValueHeadersSerializer(BaseHeadersSerializer): + def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: + """ + When using REST APIs, headers can be encoded using the `multiValueHeaders` key on the response. + This is also the case when using an ALB integration with the `multiValueHeaders` option enabled. + The solution covers headers with just one key or multiple keys. + + https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format + https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers-response + """ + payload: Dict[str, List[str]] = defaultdict(list) + + for key, values in headers.items(): + if isinstance(values, str): + payload[key].append(values) + else: + for value in values: + payload[key].append(value) + + if cookies: + payload.setdefault("Set-Cookie", []) + for cookie in cookies: + payload["Set-Cookie"].append(cookie) + + return {"multiValueHeaders": payload} + + +class SingleValueHeadersSerializer(BaseHeadersSerializer): + def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: + """ + The ALB integration has `multiValueHeaders` disabled by default. + If we try to set multiple headers with the same key, or more than one cookie, print a warning. + + https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#respond-to-load-balancer + """ + payload: Dict[str, Dict[str, str]] = {} + payload.setdefault("headers", {}) + + if cookies: + if len(cookies) > 1: + warnings.warn( + "Can't encode more than one cookie in the response. Sending the last cookie only. " + "Did you enable multiValueHeaders on the ALB Target Group?" + ) + + # We can only send one cookie, send the last one + payload["headers"]["Set-Cookie"] = cookies[-1] + + for key, values in headers.items(): + if isinstance(values, str): + payload["headers"][key] = values + else: + if len(values) > 1: + warnings.warn( + f"Can't encode more than one header value for the same key ('{key}') in the response. " + "Did you enable multiValueHeaders on the ALB Target Group?" + ) + + # We can only set one header per key, send the last one + payload["headers"][key] = values[-1] + + return payload diff --git a/aws_lambda_powertools/utilities/data_classes/alb_event.py b/aws_lambda_powertools/utilities/data_classes/alb_event.py index 159779c86a7..1bd49fd05b6 100644 --- a/aws_lambda_powertools/utilities/data_classes/alb_event.py +++ b/aws_lambda_powertools/utilities/data_classes/alb_event.py @@ -1,5 +1,10 @@ from typing import Dict, List, Optional +from aws_lambda_powertools.shared.headers_serializer import ( + BaseHeadersSerializer, + MultiValueHeadersSerializer, + SingleValueHeadersSerializer, +) from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent, DictWrapper @@ -30,3 +35,11 @@ def multi_value_query_string_parameters(self) -> Optional[Dict[str, List[str]]]: @property def multi_value_headers(self) -> Optional[Dict[str, List[str]]]: return self.get("multiValueHeaders") + + def header_serializer(self) -> BaseHeadersSerializer: + # When using the ALB integration, the `multiValueHeaders` feature can be disabled (default) or enabled. + # We can determine if the feature is enabled by looking if the event has a `multiValueHeaders` key. + if self.multi_value_headers: + return MultiValueHeadersSerializer() + + return SingleValueHeadersSerializer() diff --git a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py index be374aba398..030d9739fa4 100644 --- a/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +++ b/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py @@ -1,5 +1,10 @@ from typing import Any, Dict, List, Optional +from aws_lambda_powertools.shared.headers_serializer import ( + BaseHeadersSerializer, + HttpApiHeadersSerializer, + MultiValueHeadersSerializer, +) from aws_lambda_powertools.utilities.data_classes.common import ( BaseProxyEvent, BaseRequestContext, @@ -106,6 +111,9 @@ def path_parameters(self) -> Optional[Dict[str, str]]: def stage_variables(self) -> Optional[Dict[str, str]]: return self.get("stageVariables") + def header_serializer(self) -> BaseHeadersSerializer: + return MultiValueHeadersSerializer() + class RequestContextV2AuthorizerIam(DictWrapper): @property @@ -250,3 +258,6 @@ def path(self) -> str: def http_method(self) -> str: """The HTTP method used. Valid values include: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT.""" return self.request_context.http.method + + def header_serializer(self): + return HttpApiHeadersSerializer() diff --git a/aws_lambda_powertools/utilities/data_classes/common.py b/aws_lambda_powertools/utilities/data_classes/common.py index 2109ee3dd3e..ffd608f3015 100644 --- a/aws_lambda_powertools/utilities/data_classes/common.py +++ b/aws_lambda_powertools/utilities/data_classes/common.py @@ -2,6 +2,8 @@ import json from typing import Any, Dict, Optional +from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer + class DictWrapper: """Provides a single read only access to a wrapper dict""" @@ -127,6 +129,9 @@ def get_header_value( """ return get_header_value(self.headers, name, default_value, case_sensitive) + def header_serializer(self) -> BaseHeadersSerializer: + raise NotImplementedError() + class RequestContextClientCert(DictWrapper): @property diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index f4f45a051f8..c4cae718289 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -312,11 +312,18 @@ For convenience, these are the default values when using `CORSConfig` to enable ### Fine grained responses -You can use the `Response` class to have full control over the response, for example you might want to add additional headers or set a custom Content-type. +You can use the `Response` class to have full control over the response. For example, you might want to add additional headers, cookies, or set a custom Content-type. + +???+ info + Powertools serializes headers and cookies according to the type of input event. + Some event sources require headers and cookies to be encoded as `multiValueHeaders`. + +???+ warning "Using multiple values for HTTP headers in ALB?" + Make sure you [enable the multi value headers feature](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers) to serialize response headers correctly. === "fine_grained_responses.py" - ```python hl_lines="7 24-28" + ```python hl_lines="7 24-29" --8<-- "examples/event_handler_rest/src/fine_grained_responses.py" ``` diff --git a/docs/upgrade.md b/docs/upgrade.md new file mode 100644 index 00000000000..91ad54e42d3 --- /dev/null +++ b/docs/upgrade.md @@ -0,0 +1,57 @@ +--- +title: Upgrade guide +description: Guide to update between major Powertools versions +--- + + + +## Migrate to v2 from v1 + +The transition from Powertools for Python v1 to v2 is as painless as possible, as we aimed for minimal breaking changes. +Changes at a glance: + +* The API for **event handler's `Response`** has minor changes to support multi value headers and cookies. + +???+ important + Powertools for Python v2 drops suport for Python 3.6, following the Python 3.6 End-Of-Life (EOL) reached on December 23, 2021. + +### Initial Steps + +Before you start, we suggest making a copy of your current working project or create a new branch with git. + +1. **Upgrade** Python to at least v3.7 + +2. **Ensure** you have the latest `aws-lambda-powertools` + + ```bash + pip install aws-lambda-powertools -U + ``` + +3. **Review** the following sections to confirm whether they affect your code + +## Event Handler Response (headers and cookies) + +The `Response` class of the event handler utility changed slightly: + +1. The `headers` parameter now expects either a value or list of values per header (type `Union[str, Dict[str, List[str]]]`) +2. We introduced a new `cookies` parameter (type `List[str]`) + +???+ note + Code that set headers as `Dict[str, str]` will still work unchanged. + +```python hl_lines="6 12 13" +@app.get("/todos") +def get_todos(): + # Before + return Response( + # ... + headers={"Content-Type": "text/plain"} + ) + + # After + return Response( + # ... + headers={"Content-Type": ["text/plain"]}, + cookies=["CookieName=CookieValue"] + ) +``` diff --git a/examples/event_handler_rest/src/binary_responses_output.json b/examples/event_handler_rest/src/binary_responses_output.json index 0938dee6811..ec59d251732 100644 --- a/examples/event_handler_rest/src/binary_responses_output.json +++ b/examples/event_handler_rest/src/binary_responses_output.json @@ -1,7 +1,7 @@ { "body": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICAgIDx0aXRsZT5BV1MgTGFtYmRhPC90aXRsZT4KICAgIDxkZWZzPgogICAgICAgIDxsaW5lYXJHcmFkaWVudCB4MT0iMCUiIHkxPSIxMDAlIiB4Mj0iMTAwJSIgeTI9IjAlIiBpZD0ibGluZWFyR3JhZGllbnQtMSI+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNDODUxMUIiIG9mZnNldD0iMCUiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0ZGOTkwMCIgb2Zmc2V0PSIxMDAlIj48L3N0b3A+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDwvZGVmcz4KICAgIDxnPgogICAgICAgIDxyZWN0IGZpbGw9InVybCgjbGluZWFyR3JhZGllbnQtMSkiIHg9IjAiIHk9IjAiIHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2Ij48L3JlY3Q+CiAgICAgICAgPHBhdGggZD0iTTg5LjYyNDExMjYsMjExLjIgTDQ5Ljg5MDMyNzcsMjExLjIgTDkzLjgzNTQ4MzIsMTE5LjM0NzIgTDExMy43NDcyOCwxNjAuMzM5MiBMODkuNjI0MTEyNiwyMTEuMiBaIE05Ni43MDI5MzU3LDExMC41Njk2IEM5Ni4xNjQwODU4LDEwOS40NjU2IDk1LjA0MTQ4MTMsMTA4Ljc2NDggOTMuODE2MjM4NCwxMDguNzY0OCBMOTMuODA2NjE2MywxMDguNzY0OCBDOTIuNTcxNzUxNCwxMDguNzY4IDkxLjQ0OTE0NjYsMTA5LjQ3NTIgOTAuOTE5OTE4NywxMTAuNTg1NiBMNDEuOTEzNDIwOCwyMTMuMDIwOCBDNDEuNDM4NzE5NywyMTQuMDEyOCA0MS41MDYwNzU4LDIxNS4xNzc2IDQyLjA5NjI0NTEsMjE2LjEwODggQzQyLjY3OTk5OTQsMjE3LjAzNjggNDMuNzA2MzgwNSwyMTcuNiA0NC44MDY1MzMxLDIxNy42IEw5MS42NTQ0MjMsMjE3LjYgQzkyLjg5NTcwMjcsMjE3LjYgOTQuMDIxNTE0OSwyMTYuODg2NCA5NC41NTM5NTAxLDIxNS43Njk2IEwxMjAuMjAzODU5LDE2MS42ODk2IEMxMjAuNjE3NjE5LDE2MC44MTI4IDEyMC42MTQ0MTIsMTU5Ljc5ODQgMTIwLjE4NzgyMiwxNTguOTI4IEw5Ni43MDI5MzU3LDExMC41Njk2IFogTTIwNy45ODUxMTcsMjExLjIgTDE2OC41MDc5MjgsMjExLjIgTDEwNS4xNzM3ODksNzguNjI0IEMxMDQuNjQ0NTYxLDc3LjUxMDQgMTAzLjUxNTU0MSw3Ni44IDEwMi4yNzc0NjksNzYuOCBMNzYuNDQ3OTQzLDc2LjggTDc2LjQ3NjgwOTksNDQuOCBMMTI3LjEwMzA2Niw0NC44IEwxOTAuMTQ1MzI4LDE3Ny4zNzI4IEMxOTAuNjc0NTU2LDE3OC40ODY0IDE5MS44MDM1NzUsMTc5LjIgMTkzLjA0MTY0NywxNzkuMiBMMjA3Ljk4NTExNywxNzkuMiBMMjA3Ljk4NTExNywyMTEuMiBaIE0yMTEuMTkyNTU4LDE3Mi44IEwxOTUuMDcxOTU4LDE3Mi44IEwxMzIuMDI5Njk2LDQwLjIyNzIgQzEzMS41MDA0NjgsMzkuMTEzNiAxMzAuMzcxNDQ5LDM4LjQgMTI5LjEzMDE2OSwzOC40IEw3My4yNzI1NzYsMzguNCBDNzEuNTA1Mjc1OCwzOC40IDcwLjA2ODM0MjEsMzkuODMwNCA3MC4wNjUxMzQ0LDQxLjU5NjggTDcwLjAyOTg1MjgsNzkuOTk2OCBDNzAuMDI5ODUyOCw4MC44NDggNzAuMzYzNDI2Niw4MS42NjA4IDcwLjk2OTYzMyw4Mi4yNjI0IEM3MS41Njk0MjQ2LDgyLjg2NCA3Mi4zODQxMTQ2LDgzLjIgNzMuMjM3Mjk0MSw4My4yIEwxMDAuMjUzNTczLDgzLjIgTDE2My41OTA5MiwyMTUuNzc2IEMxNjQuMTIzMzU1LDIxNi44ODk2IDE2NS4yNDU5NiwyMTcuNiAxNjYuNDg0MDMyLDIxNy42IEwyMTEuMTkyNTU4LDIxNy42IEMyMTIuOTY2Mjc0LDIxNy42IDIxNC40LDIxNi4xNjY0IDIxNC40LDIxNC40IEwyMTQuNCwxNzYgQzIxNC40LDE3NC4yMzM2IDIxMi45NjYyNzQsMTcyLjggMjExLjE5MjU1OCwxNzIuOCBMMjExLjE5MjU1OCwxNzIuOCBaIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==", - "headers": { - "Content-Type": "image/svg+xml" + "multiValueHeaders": { + "Content-Type": ["image/svg+xml"] }, "isBase64Encoded": true, "statusCode": 200 diff --git a/examples/event_handler_rest/src/compressing_responses_output.json b/examples/event_handler_rest/src/compressing_responses_output.json index 0836b3aa726..60a63966494 100644 --- a/examples/event_handler_rest/src/compressing_responses_output.json +++ b/examples/event_handler_rest/src/compressing_responses_output.json @@ -1,8 +1,8 @@ { "statusCode": 200, - "headers": { - "Content-Type": "application/json", - "Content-Encoding": "gzip" + "multiValueHeaders": { + "Content-Type": ["application/json"], + "Content-Encoding": ["gzip"] }, "body": "H4sIAAAAAAACE42STU4DMQyFrxJl3QXln96AMyAW7sSDLCVxiJ0Kqerd8TCCUOgii1EmP/783pOPXjmw+N3L0TfB+hz8brvxtC5KGtHvfMCIkzZx0HT5MPmNnziViIr2dIYoeNr8Q1x3xHsjcVadIbkZJoq2RXU8zzQROLseQ9505NzeCNQdMJNBE+UmY4zbzjAJhWtlZ57sB84BWtul+rteH2HPlVgWARwjqXkxpklK5gmEHAQqJBMtFsGVygcKmNVRjG0wxvuzGF2L0dpVUOKMC3bfJNjJgWMrCuZk7cUp02AiD72D6WKHHwUDKbiJs6AZ0VZXKOUx4uNvzdxT+E4mLcMA+6G8nzrLQkaxkNEVrFKW2VGbJCoCY7q2V3+tiv5kGThyxfTecDWbgGz/NfYXhL6ePgF9PnFdPgMAAA==", "isBase64Encoded": true diff --git a/examples/event_handler_rest/src/fine_grained_responses.py b/examples/event_handler_rest/src/fine_grained_responses.py index 3e477160307..4892de9c798 100644 --- a/examples/event_handler_rest/src/fine_grained_responses.py +++ b/examples/event_handler_rest/src/fine_grained_responses.py @@ -19,13 +19,14 @@ def get_todos(): todos: requests.Response = requests.get("https://jsonplaceholder.typicode.com/todos") todos.raise_for_status() - custom_headers = {"X-Transaction-Id": f"{uuid4()}"} + custom_headers = {"X-Transaction-Id": [f"{uuid4()}"]} return Response( status_code=HTTPStatus.OK.value, # 200 content_type=content_types.APPLICATION_JSON, body=todos.json()[:10], headers=custom_headers, + cookies=["=; Secure; Expires="], ) diff --git a/examples/event_handler_rest/src/fine_grained_responses_output.json b/examples/event_handler_rest/src/fine_grained_responses_output.json index c3d58098e80..1ce606839b1 100644 --- a/examples/event_handler_rest/src/fine_grained_responses_output.json +++ b/examples/event_handler_rest/src/fine_grained_responses_output.json @@ -1,8 +1,9 @@ { "statusCode": 200, - "headers": { - "Content-Type": "application/json", - "X-Transaction-Id": "3490eea9-791b-47a0-91a4-326317db61a9" + "multiValueHeaders": { + "Content-Type": ["application/json"], + "X-Transaction-Id": ["3490eea9-791b-47a0-91a4-326317db61a9"], + "Set-Cookie": ["=; Secure; Expires="] }, "body": "{\"todos\":[{\"userId\":1,\"id\":1,\"title\":\"delectus aut autem\",\"completed\":false},{\"userId\":1,\"id\":2,\"title\":\"quis ut nam facilis et officia qui\",\"completed\":false},{\"userId\":1,\"id\":3,\"title\":\"fugiat veniam minus\",\"completed\":false},{\"userId\":1,\"id\":4,\"title\":\"et porro tempora\",\"completed\":true},{\"userId\":1,\"id\":5,\"title\":\"laboriosam mollitia et enim quasi adipisci quia provident illum\",\"completed\":false},{\"userId\":1,\"id\":6,\"title\":\"qui ullam ratione quibusdam voluptatem quia omnis\",\"completed\":false},{\"userId\":1,\"id\":7,\"title\":\"illo expedita consequatur quia in\",\"completed\":false},{\"userId\":1,\"id\":8,\"title\":\"quo adipisci enim quam ut ab\",\"completed\":true},{\"userId\":1,\"id\":9,\"title\":\"molestiae perspiciatis ipsa\",\"completed\":false},{\"userId\":1,\"id\":10,\"title\":\"illo est ratione doloremque quia maiores aut\",\"completed\":true}]}", "isBase64Encoded": false diff --git a/examples/event_handler_rest/src/getting_started_rest_api_resolver_output.json b/examples/event_handler_rest/src/getting_started_rest_api_resolver_output.json index 2ef3714531f..24d2b5c6dbc 100644 --- a/examples/event_handler_rest/src/getting_started_rest_api_resolver_output.json +++ b/examples/event_handler_rest/src/getting_started_rest_api_resolver_output.json @@ -1,7 +1,7 @@ { "statusCode": 200, - "headers": { - "Content-Type": "application/json" + "multiValueHeaders": { + "Content-Type": ["application/json"] }, "body": "{\"todos\":[{\"userId\":1,\"id\":1,\"title\":\"delectus aut autem\",\"completed\":false},{\"userId\":1,\"id\":2,\"title\":\"quis ut nam facilis et officia qui\",\"completed\":false},{\"userId\":1,\"id\":3,\"title\":\"fugiat veniam minus\",\"completed\":false},{\"userId\":1,\"id\":4,\"title\":\"et porro tempora\",\"completed\":true},{\"userId\":1,\"id\":5,\"title\":\"laboriosam mollitia et enim quasi adipisci quia provident illum\",\"completed\":false},{\"userId\":1,\"id\":6,\"title\":\"qui ullam ratione quibusdam voluptatem quia omnis\",\"completed\":false},{\"userId\":1,\"id\":7,\"title\":\"illo expedita consequatur quia in\",\"completed\":false},{\"userId\":1,\"id\":8,\"title\":\"quo adipisci enim quam ut ab\",\"completed\":true},{\"userId\":1,\"id\":9,\"title\":\"molestiae perspiciatis ipsa\",\"completed\":false},{\"userId\":1,\"id\":10,\"title\":\"illo est ratione doloremque quia maiores aut\",\"completed\":true}]}", "isBase64Encoded": false diff --git a/examples/event_handler_rest/src/setting_cors_output.json b/examples/event_handler_rest/src/setting_cors_output.json index ca86e892d38..19660941e91 100644 --- a/examples/event_handler_rest/src/setting_cors_output.json +++ b/examples/event_handler_rest/src/setting_cors_output.json @@ -1,9 +1,9 @@ { "statusCode": 200, - "headers": { - "Content-Type": "application/json", - "Access-Control-Allow-Origin": "https://www.example.com", - "Access-Control-Allow-Headers": "Authorization,Content-Type,X-Amz-Date,X-Amz-Security-Token,X-Api-Key" + "multiValueHeaders": { + "Content-Type": ["application/json"], + "Access-Control-Allow-Origin": ["https://www.example.com"], + "Access-Control-Allow-Headers": ["Authorization,Content-Type,X-Amz-Date,X-Amz-Security-Token,X-Api-Key"] }, "body": "{\"todos\":[{\"userId\":1,\"id\":1,\"title\":\"delectus aut autem\",\"completed\":false},{\"userId\":1,\"id\":2,\"title\":\"quis ut nam facilis et officia qui\",\"completed\":false},{\"userId\":1,\"id\":3,\"title\":\"fugiat veniam minus\",\"completed\":false},{\"userId\":1,\"id\":4,\"title\":\"et porro tempora\",\"completed\":true},{\"userId\":1,\"id\":5,\"title\":\"laboriosam mollitia et enim quasi adipisci quia provident illum\",\"completed\":false},{\"userId\":1,\"id\":6,\"title\":\"qui ullam ratione quibusdam voluptatem quia omnis\",\"completed\":false},{\"userId\":1,\"id\":7,\"title\":\"illo expedita consequatur quia in\",\"completed\":false},{\"userId\":1,\"id\":8,\"title\":\"quo adipisci enim quam ut ab\",\"completed\":true},{\"userId\":1,\"id\":9,\"title\":\"molestiae perspiciatis ipsa\",\"completed\":false},{\"userId\":1,\"id\":10,\"title\":\"illo est ratione doloremque quia maiores aut\",\"completed\":true}]}", "isBase64Encoded": false diff --git a/mkdocs.yml b/mkdocs.yml index 171cf36eb13..59fcdfa6a08 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,6 +10,7 @@ nav: - Tutorial: tutorial/index.md - Roadmap: roadmap.md - API reference: api/" target="_blank + - Upgrade guide: upgrade.md - Core utilities: - core/tracer.md - core/logger.md diff --git a/poetry.lock b/poetry.lock index 9b94cb96cfe..43c92ec29ac 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,30 +8,62 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "21.4.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +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"] [[package]] name = "aws-cdk-lib" -version = "2.23.0" +version = "2.38.1" description = "Version 2 of the AWS Cloud Development Kit library" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = "~=3.7" + +[package.dependencies] +constructs = ">=10.0.0,<11.0.0" +jsii = ">=1.63.2,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<2.14.0" + +[[package]] +name = "aws-cdk.aws-apigatewayv2-alpha" +version = "2.38.1a0" +description = "The CDK Construct Library for AWS::APIGatewayv2" +category = "dev" +optional = false +python-versions = "~=3.7" + +[package.dependencies] +aws-cdk-lib = ">=2.38.1,<3.0.0" +constructs = ">=10.0.0,<11.0.0" +jsii = ">=1.63.2,<2.0.0" +publication = ">=0.0.3" +typeguard = ">=2.13.3,<2.14.0" + +[[package]] +name = "aws-cdk.aws-apigatewayv2-integrations-alpha" +version = "2.38.1a0" +description = "Integrations for AWS APIGateway V2" +category = "dev" +optional = false +python-versions = "~=3.7" [package.dependencies] +aws-cdk-lib = ">=2.38.1,<3.0.0" +"aws-cdk.aws-apigatewayv2-alpha" = "2.38.1.a0" constructs = ">=10.0.0,<11.0.0" -jsii = ">=1.57.0,<2.0.0" +jsii = ">=1.63.2,<2.0.0" publication = ">=0.0.3" +typeguard = ">=2.13.3,<2.14.0" [[package]] name = "aws-xray-sdk" @@ -47,11 +79,11 @@ wrapt = "*" [[package]] name = "bandit" -version = "1.7.1" +version = "1.7.4" description = "Security oriented static analyser for python code." category = "dev" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [package.dependencies] colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} @@ -59,57 +91,57 @@ GitPython = ">=1.0.1" PyYAML = ">=5.3.1" stevedore = ">=1.20.0" +[package.extras] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml"] +toml = ["toml"] +yaml = ["pyyaml"] + [[package]] name = "black" -version = "21.12b0" +version = "22.6.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] -click = ">=7.1.2" -dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} +click = ">=8.0.0" mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0,<1" +pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = ">=0.2.6,<2.0.0" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = [ - {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, - {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, -] +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -python2 = ["typed-ast (>=1.4.3)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.23.10" +version = "1.24.58" description = "The AWS SDK for Python" category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] -botocore = ">=1.26.10,<1.27.0" +botocore = ">=1.27.58,<1.28.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.5.0,<0.6.0" +s3transfer = ">=0.6.0,<0.7.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.26.10" +version = "1.27.58" description = "Low-level, data-driven core of boto 3." category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] jmespath = ">=0.7.1,<2.0.0" @@ -117,21 +149,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<1.27" [package.extras] -crt = ["awscrt (==0.13.8)"] - -[[package]] -name = "cattrs" -version = "1.0.0" -description = "Composable complex class support for attrs." -category = "dev" -optional = false -python-versions = "*" - -[package.dependencies] -attrs = ">=17.3" - -[package.extras] -dev = ["bumpversion", "wheel", "watchdog", "flake8", "tox", "coverage", "sphinx", "pytest", "hypothesis", "pendulum"] +crt = ["awscrt (==0.14.0)"] [[package]] name = "cattrs" @@ -156,22 +174,22 @@ python-versions = ">=3.6" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.1.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "dev" optional = false -python-versions = ">=3.5.0" +python-versions = ">=3.6.0" [package.extras] unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.4" +version = "8.1.3" description = "Composable command line interface toolkit" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -187,38 +205,31 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "constructs" -version = "10.1.1" +version = "10.1.85" description = "A programming model for software-defined state" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = "~=3.7" [package.dependencies] -jsii = ">=1.57.0,<2.0.0" +jsii = ">=1.65.0,<2.0.0" publication = ">=0.0.3" +typeguard = ">=2.13.3,<2.14.0" [[package]] name = "coverage" -version = "6.2" +version = "6.4.4" description = "Code coverage measurement for Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -tomli = {version = "*", optional = true, markers = "extra == \"toml\""} +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli"] -[[package]] -name = "dataclasses" -version = "0.8" -description = "A backport of the dataclasses module for Python 3.6" -category = "main" -optional = false -python-versions = ">=3.6, <3.7" - [[package]] name = "decorator" version = "5.1.1" @@ -236,8 +247,8 @@ optional = true python-versions = ">=3.6,<4.0" [package.extras] -dnssec = ["cryptography (>=2.6,<37.0)"] curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] +dnssec = ["cryptography (>=2.6,<37.0)"] doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"] idna = ["idna (>=2.1,<4.0)"] trio = ["trio (>=0.14,<0.20)"] @@ -294,7 +305,7 @@ optional = false python-versions = "*" [package.extras] -devel = ["colorama", "jsonschema", "json-spec", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] [[package]] name = "flake8" @@ -310,9 +321,22 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" +[[package]] +name = "flake8-black" +version = "0.3.3" +description = "flake8 plugin to call black as a code style validator" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +black = ">=22.1.0" +flake8 = ">=3.0.0" +tomli = "*" + [[package]] name = "flake8-bugbear" -version = "22.7.1" +version = "22.8.23" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." category = "dev" optional = false @@ -341,28 +365,27 @@ test = ["coverage", "coveralls", "mock", "pytest", "pytest-cov"] [[package]] name = "flake8-comprehensions" -version = "3.7.0" +version = "3.10.0" description = "A flake8 plugin to help you write better list/set/dict comprehensions." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] -flake8 = ">=3.0,<3.2.0 || >3.2.0,<5" +flake8 = ">=3.0,<3.2.0 || >3.2.0" importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "flake8-debugger" -version = "4.0.0" +version = "4.1.2" description = "ipdb/pdb statement checker plugin for flake8" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] flake8 = ">=3.0" pycodestyle = "*" -six = "*" [[package]] name = "flake8-eradicate" @@ -428,7 +451,7 @@ python-versions = "*" python-dateutil = ">=2.8.1" [package.extras] -dev = ["twine", "markdown", "flake8", "wheel"] +dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "gitdb" @@ -443,15 +466,15 @@ smmap = ">=3.0.1,<6" [[package]] name = "gitpython" -version = "3.1.20" -description = "Python Git Library" +version = "3.1.27" +description = "GitPython is a python library used to interact with Git repositories" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] gitdb = ">=4.0.1,<5" -typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} [[package]] name = "idna" @@ -474,24 +497,9 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] +docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] perf = ["ipython"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"] - -[[package]] -name = "importlib-resources" -version = "5.4.0" -description = "Read resources from Python packages" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["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 = "iniconfig" @@ -510,18 +518,18 @@ optional = false python-versions = ">=3.6.1,<4.0" [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] +requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.2" description = "A very fast and expressive template engine." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] MarkupSafe = ">=2.0" @@ -531,44 +539,44 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jmespath" -version = "0.10.0" +version = "1.0.1" description = "JSON Matching Expressions" category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.7" [[package]] name = "jsii" -version = "1.57.0" +version = "1.65.0" description = "Python client for jsii runtime" category = "dev" optional = false -python-versions = "~=3.6" +python-versions = "~=3.7" [package.dependencies] -attrs = ">=21.2,<22.0" -cattrs = [ - {version = ">=1.0.0,<1.1.0", markers = "python_version < \"3.7\""}, - {version = ">=1.8,<22.2", markers = "python_version >= \"3.7\""}, -] -importlib-resources = {version = "*", markers = "python_version < \"3.7\""} +attrs = ">=21.2,<23.0" +cattrs = ">=1.8,<22.2" +publication = ">=0.0.3" python-dateutil = "*" +typeguard = ">=2.13.3,<2.14.0" typing-extensions = ">=3.7,<5.0" [[package]] name = "mako" -version = "1.1.6" -description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +version = "1.2.1" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.7" [package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} MarkupSafe = ">=0.9.2" [package.extras] babel = ["babel"] lingua = ["lingua"] +testing = ["pytest"] [[package]] name = "mando" @@ -600,11 +608,11 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.0.1" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "mccabe" @@ -878,14 +886,14 @@ markdown = ">=3.0" [[package]] name = "platformdirs" -version = "2.4.0" +version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] @@ -944,12 +952,11 @@ optional = true python-versions = ">=3.6.1" [package.dependencies] -dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} typing-extensions = ">=3.7.4.3" [package.extras] -email = ["email-validator (>=1.0.3)"] dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] [[package]] name = "pyflakes" @@ -983,22 +990,22 @@ markdown = ">=3.2" [[package]] name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.8" [package.extras] diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.0.1" +version = "7.1.2" description = "pytest: simple powerful testing with Python" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} @@ -1058,7 +1065,7 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pytest-forked" @@ -1074,17 +1081,17 @@ pytest = ">=3.10" [[package]] name = "pytest-mock" -version = "3.6.1" +version = "3.8.2" description = "Thin-wrapper around the mock package for easier use with pytest" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] pytest = ">=5.0" [package.extras] -dev = ["pre-commit", "tox", "pytest-asyncio"] +dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytest-xdist" @@ -1157,21 +1164,21 @@ mando = ">=0.6,<0.7" [[package]] name = "requests" -version = "2.27.1" +version = "2.28.1" description = "Python HTTP for Humans." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7, <4" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" urllib3 = ">=1.21.1,<1.27" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "retry" @@ -1210,11 +1217,11 @@ python-versions = ">=3.5" [[package]] name = "s3transfer" -version = "0.5.2" +version = "0.6.0" description = "An Amazon S3 Transfer Manager" category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">= 3.7" [package.dependencies] botocore = ">=1.12.36,<2.0a.0" @@ -1252,11 +1259,11 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[package]] name = "tomli" -version = "1.2.3" +version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "typed-ast" @@ -1266,6 +1273,18 @@ category = "dev" optional = false python-versions = ">=3.6" +[[package]] +name = "typeguard" +version = "2.13.3" +description = "Run-time type checker for Python" +category = "dev" +optional = false +python-versions = ">=3.5.3" + +[package.extras] +doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["mypy", "pytest", "typing-extensions"] + [[package]] name = "types-requests" version = "2.28.9" @@ -1295,15 +1314,15 @@ python-versions = ">=3.7" [[package]] name = "urllib3" -version = "1.26.11" +version = "1.26.12" 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.*, <4" [package.extras] -brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] @@ -1347,205 +1366,193 @@ optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +testing = ["func-timeout", "jaraco.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] pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" -python-versions = "^3.6.2" -content-hash = "0a9e21c2f15825934ad6c786121da020c4a964c5a0dd138e0e8ae09c0865a055" +python-versions = "^3.7.4" +content-hash = "5f36bb2dc0877d19d3a6405df72819c3678fc97fa5ae3e31f9b125c40f39404f" [metadata.files] -atomicwrites = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] +atomicwrites = [] attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] aws-cdk-lib = [ - {file = "aws-cdk-lib-2.23.0.tar.gz", hash = "sha256:3e07d1c6b320795d38567be183e56c2125b4c4492589775257aabec3d3e2a384"}, - {file = "aws_cdk_lib-2.23.0-py3-none-any.whl", hash = "sha256:1ec04a146d3364cd0fc4da08e3f8ca25e28df68abaa90641936db17a415ca4bc"}, + {file = "aws-cdk-lib-2.38.1.tar.gz", hash = "sha256:5d56effc85fc998de5277aa87e89b2177564b43111a7e331bb8b83c0cd8e96ee"}, + {file = "aws_cdk_lib-2.38.1-py3-none-any.whl", hash = "sha256:400062e9f021412c470cbde8125ee4db68a13af1d501a03512ef46c4a026ab2e"}, +] +"aws-cdk.aws-apigatewayv2-alpha" = [ + {file = "aws-cdk.aws-apigatewayv2-alpha-2.38.1a0.tar.gz", hash = "sha256:a51a5cf462043f783b03b4e6a92e9fc280acff77781924d5730d53868502fbe9"}, + {file = "aws_cdk.aws_apigatewayv2_alpha-2.38.1a0-py3-none-any.whl", hash = "sha256:5345959a98b7fe405a9779fc7ea42b3453f0d550ccf257bbc4d9e9d5830c6046"}, ] -aws-xray-sdk = [ - {file = "aws-xray-sdk-2.10.0.tar.gz", hash = "sha256:9b14924fd0628cf92936055864655354003f0b1acc3e1c3ffde6403d0799dd7a"}, - {file = "aws_xray_sdk-2.10.0-py2.py3-none-any.whl", hash = "sha256:7551e81a796e1a5471ebe84844c40e8edf7c218db33506d046fec61f7495eda4"}, +"aws-cdk.aws-apigatewayv2-integrations-alpha" = [ + {file = "aws-cdk.aws-apigatewayv2-integrations-alpha-2.38.1a0.tar.gz", hash = "sha256:4df15306e9d4db41f818bb3b3b67cf956ee36a87d3989b94b0c98ea152dbaa01"}, + {file = "aws_cdk.aws_apigatewayv2_integrations_alpha-2.38.1a0-py3-none-any.whl", hash = "sha256:184fe6ce9718237fe69a4ccda9d7c5d62fd0adf823269d2816b4b9a57978c204"}, ] +aws-xray-sdk = [] bandit = [ - {file = "bandit-1.7.1-py3-none-any.whl", hash = "sha256:f5acd838e59c038a159b5c621cf0f8270b279e884eadd7b782d7491c02add0d4"}, - {file = "bandit-1.7.1.tar.gz", hash = "sha256:a81b00b5436e6880fa8ad6799bc830e02032047713cbb143a12939ac67eb756c"}, + {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, + {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"}, ] black = [ - {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, - {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, + {file = "black-22.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f586c26118bc6e714ec58c09df0157fe2d9ee195c764f630eb0d8e7ccce72e69"}, + {file = "black-22.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b270a168d69edb8b7ed32c193ef10fd27844e5c60852039599f9184460ce0807"}, + {file = "black-22.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6797f58943fceb1c461fb572edbe828d811e719c24e03375fd25170ada53825e"}, + {file = "black-22.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c85928b9d5f83b23cee7d0efcb310172412fbf7cb9d9ce963bd67fd141781def"}, + {file = "black-22.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6fe02afde060bbeef044af7996f335fbe90b039ccf3f5eb8f16df8b20f77666"}, + {file = "black-22.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cfaf3895a9634e882bf9d2363fed5af8888802d670f58b279b0bece00e9a872d"}, + {file = "black-22.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94783f636bca89f11eb5d50437e8e17fbc6a929a628d82304c80fa9cd945f256"}, + {file = "black-22.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2ea29072e954a4d55a2ff58971b83365eba5d3d357352a07a7a4df0d95f51c78"}, + {file = "black-22.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e439798f819d49ba1c0bd9664427a05aab79bfba777a6db94fd4e56fae0cb849"}, + {file = "black-22.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187d96c5e713f441a5829e77120c269b6514418f4513a390b0499b0987f2ff1c"}, + {file = "black-22.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:074458dc2f6e0d3dab7928d4417bb6957bb834434516f21514138437accdbe90"}, + {file = "black-22.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a218d7e5856f91d20f04e931b6f16d15356db1c846ee55f01bac297a705ca24f"}, + {file = "black-22.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:568ac3c465b1c8b34b61cd7a4e349e93f91abf0f9371eda1cf87194663ab684e"}, + {file = "black-22.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6c1734ab264b8f7929cef8ae5f900b85d579e6cbfde09d7387da8f04771b51c6"}, + {file = "black-22.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9a3ac16efe9ec7d7381ddebcc022119794872abce99475345c5a61aa18c45ad"}, + {file = "black-22.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:b9fd45787ba8aa3f5e0a0a98920c1012c884622c6c920dbe98dbd05bc7c70fbf"}, + {file = "black-22.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ba9be198ecca5031cd78745780d65a3f75a34b2ff9be5837045dce55db83d1c"}, + {file = "black-22.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3db5b6409b96d9bd543323b23ef32a1a2b06416d525d27e0f67e74f1446c8f2"}, + {file = "black-22.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:560558527e52ce8afba936fcce93a7411ab40c7d5fe8c2463e279e843c0328ee"}, + {file = "black-22.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b154e6bbde1e79ea3260c4b40c0b7b3109ffcdf7bc4ebf8859169a6af72cd70b"}, + {file = "black-22.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4af5bc0e1f96be5ae9bd7aaec219c901a94d6caa2484c21983d043371c733fc4"}, + {file = "black-22.6.0-py3-none-any.whl", hash = "sha256:ac609cf8ef5e7115ddd07d85d988d074ed00e10fbc3445aee393e70164a2219c"}, + {file = "black-22.6.0.tar.gz", hash = "sha256:6c6d39e28aed379aec40da1c65434c77d75e65bb59a1e1c283de545fb4e7c6c9"}, ] boto3 = [ - {file = "boto3-1.23.10-py3-none-any.whl", hash = "sha256:40d08614f17a69075e175c02c5d5aab69a6153fd50e40fa7057b913ac7bf40e7"}, - {file = "boto3-1.23.10.tar.gz", hash = "sha256:2a4395e3241c20eef441d7443a5e6eaa0ee3f7114653fb9d9cef41587526f7bd"}, + {file = "boto3-1.24.58-py3-none-any.whl", hash = "sha256:edd79104b478203459a4e45a8602c83994ccd820c39fd85cc5de9aa0ee8e75d6"}, + {file = "boto3-1.24.58.tar.gz", hash = "sha256:8a888707586de7eb4ea367a4c51354d91efbe93c2e61dc02e5c98f8c8dc69584"}, ] botocore = [ - {file = "botocore-1.26.10-py3-none-any.whl", hash = "sha256:8a4a984bf901ccefe40037da11ba2abd1ddbcb3b490a492b7f218509c99fc12f"}, - {file = "botocore-1.26.10.tar.gz", hash = "sha256:5df2cf7ebe34377470172bd0bbc582cf98c5cbd02da0909a14e9e2885ab3ae9c"}, -] -cattrs = [ - {file = "cattrs-1.0.0-py2.py3-none-any.whl", hash = "sha256:616972ae3dfa6e623a40ad3cb845420e64942989152774ab055e5c2b2f89f997"}, - {file = "cattrs-1.0.0.tar.gz", hash = "sha256:b7ab5cf8ad127c42eefd01410c1c6e28569a45a255ea80ed968511873c433c7a"}, - {file = "cattrs-22.1.0-py3-none-any.whl", hash = "sha256:d55c477b4672f93606e992049f15d526dc7867e6c756cd6256d4af92e2b1e364"}, - {file = "cattrs-22.1.0.tar.gz", hash = "sha256:94b67b64cf92c994f8784c40c082177dc916e0489a73a9a36b24eb18a9db40c6"}, -] -certifi = [ - {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, - {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, + {file = "botocore-1.27.58-py3-none-any.whl", hash = "sha256:4cc12ab3b6f195292e3e34da6aa356edb8acee51e8405d048b50ccbb64a1b9f3"}, + {file = "botocore-1.27.58.tar.gz", hash = "sha256:d904ee4743bd4b2517634b012c98dcb166f82e9d20e50d8367cd078779181ec2"}, ] +cattrs = [] +certifi = [] charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, ] click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] +colorama = [] constructs = [ - {file = "constructs-10.1.1-py3-none-any.whl", hash = "sha256:c1f3deb196f54e070ded3c92c4339f73ef2b6022d35fb34908c0ebfa7ef8a640"}, - {file = "constructs-10.1.1.tar.gz", hash = "sha256:6ce0dd1352367237b5d7c51a25740482c852735d2a5e067c536acc1657f39ea5"}, + {file = "constructs-10.1.85-py3-none-any.whl", hash = "sha256:dbcdeda26e61df8855af81e915a338345ca2d33f04b2b2861ac3a19fe98c5cfd"}, + {file = "constructs-10.1.85.tar.gz", hash = "sha256:70b2b4d75760524ff903aae0056862cd83ad9b0a5b857d9aef50597c8bbf4cfc"}, ] coverage = [ - {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, - {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, - {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, - {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, - {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, - {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, - {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, - {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, - {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, - {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, - {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, - {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, - {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, - {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, - {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, - {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, - {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, - {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, - {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, - {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, -] -dataclasses = [ - {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, - {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, -] -decorator = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, -] + {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, + {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, + {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, + {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, + {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, + {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, + {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, + {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, + {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, + {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, + {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, + {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, + {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, + {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, + {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, + {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, +] +decorator = [] dnspython = [ {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"}, {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"}, ] -email-validator = [ - {file = "email_validator-1.2.1-py2.py3-none-any.whl", hash = "sha256:c8589e691cf73eb99eed8d10ce0e9cbb05a0886ba920c8bcb7c82873f4c5789c"}, - {file = "email_validator-1.2.1.tar.gz", hash = "sha256:6757aea012d40516357c0ac2b1a4c31219ab2f899d26831334c5d069e8b6c3d8"}, -] +email-validator = [] eradicate = [ {file = "eradicate-2.1.0-py3-none-any.whl", hash = "sha256:8bfaca181db9227dc88bdbce4d051a9627604c2243e7d85324f6d6ce0fd08bb2"}, {file = "eradicate-2.1.0.tar.gz", hash = "sha256:aac7384ab25b1bf21c4c012de9b4bf8398945a14c98c911545b2ea50ab558014"}, ] -exceptiongroup = [ - {file = "exceptiongroup-1.0.0rc8-py3-none-any.whl", hash = "sha256:ab0a968e1ef769e55d9a596f4a89f7be9ffedbc9fdefdb77cc68cf5c33ce1035"}, - {file = "exceptiongroup-1.0.0rc8.tar.gz", hash = "sha256:6990c24f06b8d33c8065cfe43e5e8a4bfa384e0358be036af9cc60b6321bd11a"}, -] -execnet = [ - {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, - {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, -] -fastjsonschema = [ - {file = "fastjsonschema-2.16.1-py3-none-any.whl", hash = "sha256:2f7158c4de792555753d6c2277d6a2af2d406dfd97aeca21d17173561ede4fe6"}, - {file = "fastjsonschema-2.16.1.tar.gz", hash = "sha256:d6fa3ffbe719768d70e298b9fb847484e2bdfdb7241ed052b8d57a9294a8c334"}, -] +exceptiongroup = [] +execnet = [] +fastjsonschema = [] flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] -flake8-bugbear = [ - {file = "flake8-bugbear-22.7.1.tar.gz", hash = "sha256:e450976a07e4f9d6c043d4f72b17ec1baf717fe37f7997009c8ae58064f88305"}, - {file = "flake8_bugbear-22.7.1-py3-none-any.whl", hash = "sha256:db5d7a831ef4412a224b26c708967ff816818cabae415e76b8c58df156c4b8e5"}, +flake8-black = [ + {file = "flake8-black-0.3.3.tar.gz", hash = "sha256:8211f5e20e954cb57c709acccf2f3281ce27016d4c4b989c3e51f878bb7ce12a"}, + {file = "flake8_black-0.3.3-py3-none-any.whl", hash = "sha256:7d667d0059fd1aa468de1669d77cc934b7f1feeac258d57bdae69a8e73c4cd90"}, ] -flake8-builtins = [ - {file = "flake8-builtins-1.5.3.tar.gz", hash = "sha256:09998853b2405e98e61d2ff3027c47033adbdc17f9fe44ca58443d876eb00f3b"}, - {file = "flake8_builtins-1.5.3-py2.py3-none-any.whl", hash = "sha256:7706babee43879320376861897e5d1468e396a40b8918ed7bccf70e5f90b8687"}, +flake8-bugbear = [ + {file = "flake8-bugbear-22.8.23.tar.gz", hash = "sha256:de0717d11124a082118dd08387b34fd86b2721642ec2d8e92be66cfa5ea7c445"}, + {file = "flake8_bugbear-22.8.23-py3-none-any.whl", hash = "sha256:1b0ebe0873d1cd55bf9f1588bfcb930db339018ef44a3981a26532daa9fd14a8"}, ] +flake8-builtins = [] flake8-comprehensions = [ - {file = "flake8-comprehensions-3.7.0.tar.gz", hash = "sha256:6b3218b2dde8ac5959c6476cde8f41a79e823c22feb656be2710cd2a3232cef9"}, - {file = "flake8_comprehensions-3.7.0-py3-none-any.whl", hash = "sha256:a5d7aea6315bbbd6fbcb2b4e80bff6a54d1600155e26236e555d0c6fe1d62522"}, + {file = "flake8-comprehensions-3.10.0.tar.gz", hash = "sha256:181158f7e7aa26a63a0a38e6017cef28c6adee71278ce56ce11f6ec9c4905058"}, + {file = "flake8_comprehensions-3.10.0-py3-none-any.whl", hash = "sha256:dad454fd3d525039121e98fa1dd90c46bc138708196a4ebbc949ad3c859adedb"}, ] flake8-debugger = [ - {file = "flake8-debugger-4.0.0.tar.gz", hash = "sha256:e43dc777f7db1481db473210101ec2df2bd39a45b149d7218a618e954177eda6"}, - {file = "flake8_debugger-4.0.0-py3-none-any.whl", hash = "sha256:82e64faa72e18d1bdd0000407502ebb8ecffa7bc027c62b9d4110ce27c091032"}, + {file = "flake8-debugger-4.1.2.tar.gz", hash = "sha256:52b002560941e36d9bf806fca2523dc7fb8560a295d5f1a6e15ac2ded7a73840"}, + {file = "flake8_debugger-4.1.2-py3-none-any.whl", hash = "sha256:0a5e55aeddcc81da631ad9c8c366e7318998f83ff00985a49e6b3ecf61e571bf"}, ] flake8-eradicate = [ {file = "flake8-eradicate-1.3.0.tar.gz", hash = "sha256:e4c98f00d17dc8653e3388cac2624cd81e9735de2fd4a8dcf99029633ebd7a63"}, {file = "flake8_eradicate-1.3.0-py3-none-any.whl", hash = "sha256:85a71e0c5f4e07f7c6c5fec520483561fd6bd295417d622855bdeade99242e3d"}, ] -flake8-fixme = [ - {file = "flake8-fixme-1.1.1.tar.gz", hash = "sha256:50cade07d27a4c30d4f12351478df87339e67640c83041b664724bda6d16f33a"}, - {file = "flake8_fixme-1.1.1-py2.py3-none-any.whl", hash = "sha256:226a6f2ef916730899f29ac140bed5d4a17e5aba79f00a0e3ae1eff1997cb1ac"}, -] +flake8-fixme = [] flake8-isort = [ {file = "flake8-isort-4.2.0.tar.gz", hash = "sha256:26571500cd54976bbc0cf1006ffbcd1a68dd102f816b7a1051b219616ba9fee0"}, {file = "flake8_isort-4.2.0-py3-none-any.whl", hash = "sha256:5b87630fb3719bf4c1833fd11e0d9534f43efdeba524863e15d8f14a7ef6adbf"}, ] -flake8-variables-names = [ - {file = "flake8_variables_names-0.0.4.tar.gz", hash = "sha256:d6fa0571a807c72940b5773827c5760421ea6f8206595ff0a8ecfa01e42bf2cf"}, -] -future = [ - {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, -] +flake8-variables-names = [] +future = [] ghp-import = [ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, ] -gitdb = [ - {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, - {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, -] +gitdb = [] gitpython = [ - {file = "GitPython-3.1.20-py3-none-any.whl", hash = "sha256:b1e1c269deab1b08ce65403cf14e10d2ef1f6c89e33ea7c5e5bb0222ea593b8a"}, - {file = "GitPython-3.1.20.tar.gz", hash = "sha256:df0e072a200703a65387b0cfdf0466e3bab729c0458cf6b7349d0e9877636519"}, + {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, + {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, @@ -1555,130 +1562,85 @@ importlib-metadata = [ {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"}, {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"}, ] -importlib-resources = [ - {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, - {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, -] -iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] +iniconfig = [] +isort = [] jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] jmespath = [ - {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, - {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] jsii = [ - {file = "jsii-1.57.0-py3-none-any.whl", hash = "sha256:4888091986a9ed8d50b042cc9c35a9564dd54c19e78adb890bf06d9ffac1b325"}, - {file = "jsii-1.57.0.tar.gz", hash = "sha256:ff7a3c51c1a653dd8a4342043b5f8e40b928bc617e3141e0d5d66175d22a754b"}, + {file = "jsii-1.65.0-py3-none-any.whl", hash = "sha256:47b939259ec465bc044aed6d3288b9b27a8edef2af21f1a8448e297b8429f154"}, + {file = "jsii-1.65.0.tar.gz", hash = "sha256:a09ef1f9864fe27457ba4233b3a0744a76d2562077d5b8b3a7f2242edc4a8293"}, ] mako = [ - {file = "Mako-1.1.6-py2.py3-none-any.whl", hash = "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57"}, - {file = "Mako-1.1.6.tar.gz", hash = "sha256:4e9e345a41924a954251b95b4b28e14a301145b544901332e658907a7464b6b2"}, -] -mando = [ - {file = "mando-0.6.4-py2.py3-none-any.whl", hash = "sha256:4ce09faec7e5192ffc3c57830e26acba0fd6cd11e1ee81af0d4df0657463bd1c"}, - {file = "mando-0.6.4.tar.gz", hash = "sha256:79feb19dc0f097daa64a1243db578e7674909b75f88ac2220f1c065c10a0d960"}, + {file = "Mako-1.2.1-py3-none-any.whl", hash = "sha256:df3921c3081b013c8a2d5ff03c18375651684921ae83fd12e64800b7da923257"}, + {file = "Mako-1.2.1.tar.gz", hash = "sha256:f054a5ff4743492f1aa9ecc47172cb33b42b9d993cffcc146c9de17e717b0307"}, ] +mando = [] markdown = [ {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -mergedeep = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, -] -mike = [ - {file = "mike-0.6.0-py3-none-any.whl", hash = "sha256:cef9b9c803ff5c3fbb410f51f5ceb00902a9fe16d9fabd93b69c65cf481ab5a1"}, - {file = "mike-0.6.0.tar.gz", hash = "sha256:6d6239de2a60d733da2f34617e9b9a14c4b5437423b47e524f14dc96d6ce5f2f"}, -] + {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"}, +] +mccabe = [] +mergedeep = [] +mike = [] mkdocs = [ {file = "mkdocs-1.3.1-py3-none-any.whl", hash = "sha256:fda92466393127d2da830bc6edc3a625a14b436316d1caf347690648e774c4f0"}, {file = "mkdocs-1.3.1.tar.gz", hash = "sha256:a41a2ff25ce3bbacc953f9844ba07d106233cd76c88bac1f59cb1564ac0d87ed"}, ] -mkdocs-git-revision-date-plugin = [ - {file = "mkdocs_git_revision_date_plugin-0.3.2-py3-none-any.whl", hash = "sha256:2e67956cb01823dd2418e2833f3623dee8604cdf223bddd005fe36226a56f6ef"}, -] +mkdocs-git-revision-date-plugin = [] mkdocs-material = [ {file = "mkdocs-material-8.4.1.tar.gz", hash = "sha256:92c70f94b2e1f8a05d9e05eec1c7af9dffc516802d69222329db89503c97b4f3"}, {file = "mkdocs_material-8.4.1-py2.py3-none-any.whl", hash = "sha256:319a6254819ce9d864ff79de48c43842fccfdebb43e4e6820eef75216f8cfb0a"}, ] -mkdocs-material-extensions = [ - {file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"}, - {file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"}, -] -mypy = [ - {file = "mypy-0.971-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c"}, - {file = "mypy-0.971-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5"}, - {file = "mypy-0.971-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3"}, - {file = "mypy-0.971-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655"}, - {file = "mypy-0.971-cp310-cp310-win_amd64.whl", hash = "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103"}, - {file = "mypy-0.971-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca"}, - {file = "mypy-0.971-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417"}, - {file = "mypy-0.971-cp36-cp36m-win_amd64.whl", hash = "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09"}, - {file = "mypy-0.971-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8"}, - {file = "mypy-0.971-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0"}, - {file = "mypy-0.971-cp37-cp37m-win_amd64.whl", hash = "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2"}, - {file = "mypy-0.971-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27"}, - {file = "mypy-0.971-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856"}, - {file = "mypy-0.971-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71"}, - {file = "mypy-0.971-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27"}, - {file = "mypy-0.971-cp38-cp38-win_amd64.whl", hash = "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58"}, - {file = "mypy-0.971-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6"}, - {file = "mypy-0.971-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe"}, - {file = "mypy-0.971-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9"}, - {file = "mypy-0.971-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf"}, - {file = "mypy-0.971-cp39-cp39-win_amd64.whl", hash = "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0"}, - {file = "mypy-0.971-py3-none-any.whl", hash = "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9"}, - {file = "mypy-0.971.tar.gz", hash = "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56"}, -] +mkdocs-material-extensions = [] +mypy = [] mypy-boto3-appconfig = [ {file = "mypy-boto3-appconfig-1.24.36.post1.tar.gz", hash = "sha256:e1916b3754915cb411ef977083500e1f30f81f7b3aea6ff5eed1cec91944dea6"}, {file = "mypy_boto3_appconfig-1.24.36.post1-py3-none-any.whl", hash = "sha256:a5dbe549dbebf4bc7a6cfcbfa9dff89ceb4983c042b785763ee656504bdb49f6"}, @@ -1719,44 +1681,22 @@ mypy-boto3-xray = [ {file = "mypy-boto3-xray-1.24.36.post1.tar.gz", hash = "sha256:104f1ecf7f1f6278c582201e71a7ab64843d3a3fdc8f23295cf68788cc77e9bb"}, {file = "mypy_boto3_xray-1.24.36.post1-py3-none-any.whl", hash = "sha256:97b9f0686c717c8be99ac06cb52febaf71712b4e4cd0b61ed2eb5ed012a9b5fd"}, ] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] +mypy-extensions = [] +packaging = [] +pathspec = [] pbr = [ {file = "pbr-5.10.0-py2.py3-none-any.whl", hash = "sha256:da3e18aac0a3c003e9eea1a81bd23e5a3a75d745670dcf736317b7d966887fdf"}, {file = "pbr-5.10.0.tar.gz", hash = "sha256:cfcc4ff8e698256fc17ea3ff796478b050852585aa5bae79ecd05b2ab7b39b9a"}, ] -pdoc3 = [ - {file = "pdoc3-0.10.0.tar.gz", hash = "sha256:5f22e7bcb969006738e1aa4219c75a32f34c2d62d46dc9d2fb2d3e0b0287e4b7"}, -] +pdoc3 = [] platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -publication = [ - {file = "publication-0.0.3-py2.py3-none-any.whl", hash = "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6"}, - {file = "publication-0.0.3.tar.gz", hash = "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -py-cpuinfo = [ - {file = "py-cpuinfo-8.0.0.tar.gz", hash = "sha256:5f269be0e08e33fd959de96b34cd4aeeeacac014dd8305f70eb28d06de2345c5"}, + {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, + {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] +pluggy = [] +publication = [] +py = [] +py-cpuinfo = [] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, @@ -1806,46 +1746,22 @@ pygments = [ {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, ] -pymdown-extensions = [ - {file = "pymdown_extensions-9.5-py3-none-any.whl", hash = "sha256:ec141c0f4983755349f0c8710416348d1a13753976c028186ed14f190c8061c4"}, - {file = "pymdown_extensions-9.5.tar.gz", hash = "sha256:3ef2d998c0d5fa7eb09291926d90d69391283561cf6306f85cd588a5eb5befa0"}, -] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] +pymdown-extensions = [] +pyparsing = [] pytest = [ - {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, - {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, -] -pytest-asyncio = [ - {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, - {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, -] -pytest-benchmark = [ - {file = "pytest-benchmark-3.4.1.tar.gz", hash = "sha256:40e263f912de5a81d891619032983557d62a3d85843f9a9f30b98baea0cd7b47"}, - {file = "pytest_benchmark-3.4.1-py2.py3-none-any.whl", hash = "sha256:36d2b08c4882f6f997fd3126a3d6dfd70f3249cde178ed8bbc0b73db7c20f809"}, -] -pytest-cov = [ - {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, - {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, -] -pytest-forked = [ - {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, - {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, + {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, + {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, ] +pytest-asyncio = [] +pytest-benchmark = [] +pytest-cov = [] +pytest-forked = [] pytest-mock = [ - {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, - {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, -] -pytest-xdist = [ - {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, - {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "pytest-mock-3.8.2.tar.gz", hash = "sha256:77f03f4554392558700295e05aed0b1096a20d4a60a4f3ddcde58b0c31c8fca2"}, + {file = "pytest_mock-3.8.2-py3-none-any.whl", hash = "sha256:8a9e226d6c0ef09fcf20c94eb3405c388af438a90f3e39687f84166da82d5948"}, ] +pytest-xdist = [] +python-dateutil = [] python-snappy = [ {file = "python-snappy-0.6.1.tar.gz", hash = "sha256:b6a107ab06206acc5359d4c5632bd9b22d448702a79b3169b0c62e0fb808bb2a"}, {file = "python_snappy-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b7f920eaf46ebf41bd26f9df51c160d40f9e00b7b48471c3438cb8d027f7fb9b"}, @@ -1931,72 +1847,28 @@ pyyaml = [ {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] -pyyaml-env-tag = [ - {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, - {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, -] -radon = [ - {file = "radon-5.1.0-py2.py3-none-any.whl", hash = "sha256:fa74e018197f1fcb54578af0f675d8b8e2342bd8e0b72bef8197bc4c9e645f36"}, - {file = "radon-5.1.0.tar.gz", hash = "sha256:cb1d8752e5f862fb9e20d82b5f758cbc4fb1237c92c9a66450ea0ea7bf29aeee"}, -] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] -retry = [ - {file = "retry-0.9.2-py2.py3-none-any.whl", hash = "sha256:ccddf89761fa2c726ab29391837d4327f819ea14d244c232a1d24c67a2f98606"}, - {file = "retry-0.9.2.tar.gz", hash = "sha256:f8bfa8b99b69c4506d6f5bd3b0aabf77f98cdb17f3c9fc3f5ca820033336fba4"}, -] +pyyaml-env-tag = [] +radon = [] +requests = [] +retry = [] "ruamel.yaml" = [ {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"}, ] -"ruamel.yaml.clib" = [ - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win32.whl", hash = "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win_amd64.whl", hash = "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win32.whl", hash = "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win_amd64.whl", hash = "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win32.whl", hash = "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win32.whl", hash = "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7"}, - {file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"}, -] +"ruamel.yaml.clib" = [] s3transfer = [ - {file = "s3transfer-0.5.2-py3-none-any.whl", hash = "sha256:7a6f4c4d1fdb9a2b640244008e142cbc2cd3ae34b386584ef044dd0f27101971"}, - {file = "s3transfer-0.5.2.tar.gz", hash = "sha256:95c58c194ce657a5f4fb0b9e60a84968c808888aed628cd98ab8771fe1db98ed"}, + {file = "s3transfer-0.6.0-py3-none-any.whl", hash = "sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd"}, + {file = "s3transfer-0.6.0.tar.gz", hash = "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"}, ] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] -smmap = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, -] -stevedore = [ - {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"}, - {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"}, -] +smmap = [] +stevedore = [] tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typed-ast = [ {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, @@ -2024,6 +1896,10 @@ typed-ast = [ {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] +typeguard = [ + {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, + {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, +] types-requests = [ {file = "types-requests-2.28.9.tar.gz", hash = "sha256:feaf581bd580497a47fe845d506fa3b91b484cf706ff27774e87659837de9962"}, {file = "types_requests-2.28.9-py3-none-any.whl", hash = "sha256:86cb66d3de2f53eac5c09adc42cf6547eefbd0c7e1210beca1ee751c35d96083"}, @@ -2036,7 +1912,10 @@ typing-extensions = [ {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, ] -urllib3 = [] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] watchdog = [ {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"}, @@ -2130,10 +2009,7 @@ wrapt = [ {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, ] -xenon = [ - {file = "xenon-0.9.0-py2.py3-none-any.whl", hash = "sha256:994c80c7f1c6d40596b600b93734d85a5739208f31895ef99f1e4d362caf9e35"}, - {file = "xenon-0.9.0.tar.gz", hash = "sha256:d2b9cb6c6260f771a432c1e588e51fddb17858f88f73ef641e7532f7a5f58fb8"}, -] +xenon = [] zipp = [ {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, diff --git a/pyproject.toml b/pyproject.toml index b12fdcc092a..4b75a9822ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ classifiers=[ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -20,7 +19,7 @@ keywords = ["aws_lambda_powertools", "aws", "tracing", "logging", "lambda", "pow license = "MIT-0" [tool.poetry.dependencies] -python = "^3.6.2" +python = "^3.7.4" aws-xray-sdk = "^2.8.0" fastjsonschema = "^2.14.5" boto3 = "^1.18" @@ -32,13 +31,14 @@ email-validator = {version = "*", optional = true } # issue #1148 coverage = {extras = ["toml"], version = "^6.2"} pytest = "^7.0.1" -black = "^21.12b0" +black = "^22.6.0" flake8-builtins = "^1.5.3" flake8-comprehensions = "^3.7.0" flake8-debugger = "^4.0.0" flake8-fixme = "^1.1.1" flake8-isort = "^4.1.2" flake8-variables-names = "^0.0.4" +flake8-black = "^0.3.3" isort = "^5.10.1" pytest-cov = "^3.0.0" pytest-mock = "^3.5.1" @@ -54,22 +54,24 @@ mike = "^0.6.0" mypy = "^0.971" retry = "^0.9.2" pytest-xdist = "^2.5.0" -aws-cdk-lib = "^2.23.0" +aws-cdk-lib = "^2.38.1" +"aws-cdk.aws-apigatewayv2-alpha" = "^2.38.1-alpha.0" +"aws-cdk.aws-apigatewayv2-integrations-alpha" = "^2.38.1-alpha.0" pytest-benchmark = "^3.4.1" -mypy-boto3-appconfig = { version = "^1.24.29", python = ">=3.7" } -mypy-boto3-cloudformation = { version = "^1.24.0", python = ">=3.7" } -mypy-boto3-cloudwatch = { version = "^1.24.35", python = ">=3.7" } -mypy-boto3-dynamodb = { version = "^1.24.27", python = ">=3.7" } -mypy-boto3-lambda = { version = "^1.24.0", python = ">=3.7" } -mypy-boto3-logs = { version = "^1.24.0", python = ">=3.7" } -mypy-boto3-secretsmanager = { version = "^1.24.11", python = ">=3.7" } -mypy-boto3-ssm = { version = "^1.24.0", python = ">=3.7" } -mypy-boto3-s3 = { version = "^1.24.0", python = ">=3.7" } -mypy-boto3-xray = { version = "^1.24.0", python = ">=3.7" } +mypy-boto3-appconfig = "^1.24.29" +mypy-boto3-cloudformation = "^1.24.0" +mypy-boto3-cloudwatch = "^1.24.35" +mypy-boto3-dynamodb = "^1.24.27" +mypy-boto3-lambda = "^1.24.0" +mypy-boto3-logs = "^1.24.0" +mypy-boto3-secretsmanager = "^1.24.11" +mypy-boto3-ssm = "^1.24.0" +mypy-boto3-s3 = "^1.24.0" +mypy-boto3-xray = "^1.24.0" types-requests = "^2.28.8" -typing-extensions = { version = "^4.3.0", python = ">=3.7" } +typing-extensions = "^4.3.0" python-snappy = "^0.6.1" -mkdocs-material = { version = "^8.3.9", python = ">=3.7" } +mkdocs-material = "^8.3.9" [tool.poetry.extras] pydantic = ["pydantic", "email-validator"] diff --git a/tests/e2e/event_handler/__init__.py b/tests/e2e/event_handler/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/e2e/event_handler/conftest.py b/tests/e2e/event_handler/conftest.py new file mode 100644 index 00000000000..207ec443456 --- /dev/null +++ b/tests/e2e/event_handler/conftest.py @@ -0,0 +1,28 @@ +from pathlib import Path + +import pytest + +from tests.e2e.event_handler.infrastructure import EventHandlerStack + + +@pytest.fixture(autouse=True, scope="module") +def infrastructure(request: pytest.FixtureRequest, lambda_layer_arn: str): + """Setup and teardown logic for E2E test infrastructure + + Parameters + ---------- + request : pytest.FixtureRequest + pytest request fixture to introspect absolute path to test being executed + lambda_layer_arn : str + Lambda Layer ARN + + Yields + ------ + Dict[str, str] + CloudFormation Outputs from deployed infrastructure + """ + stack = EventHandlerStack(handlers_dir=Path(f"{request.path.parent}/handlers"), layer_arn=lambda_layer_arn) + try: + yield stack.deploy() + finally: + stack.delete() diff --git a/tests/e2e/event_handler/handlers/alb_handler.py b/tests/e2e/event_handler/handlers/alb_handler.py new file mode 100644 index 00000000000..4c3f4f9dac3 --- /dev/null +++ b/tests/e2e/event_handler/handlers/alb_handler.py @@ -0,0 +1,18 @@ +from aws_lambda_powertools.event_handler import ALBResolver, Response, content_types + +app = ALBResolver() + + +@app.get("/todos") +def hello(): + return Response( + status_code=200, + content_type=content_types.TEXT_PLAIN, + body="Hello world", + cookies=["CookieMonster", "MonsterCookie"], + headers={"Foo": ["bar", "zbr"]}, + ) + + +def lambda_handler(event, context): + return app.resolve(event, context) diff --git a/tests/e2e/event_handler/handlers/api_gateway_http_handler.py b/tests/e2e/event_handler/handlers/api_gateway_http_handler.py new file mode 100644 index 00000000000..1a20b730285 --- /dev/null +++ b/tests/e2e/event_handler/handlers/api_gateway_http_handler.py @@ -0,0 +1,18 @@ +from aws_lambda_powertools.event_handler import APIGatewayHttpResolver, Response, content_types + +app = APIGatewayHttpResolver() + + +@app.get("/todos") +def hello(): + return Response( + status_code=200, + content_type=content_types.TEXT_PLAIN, + body="Hello world", + cookies=["CookieMonster", "MonsterCookie"], + headers={"Foo": ["bar", "zbr"]}, + ) + + +def lambda_handler(event, context): + return app.resolve(event, context) diff --git a/tests/e2e/event_handler/handlers/api_gateway_rest_handler.py b/tests/e2e/event_handler/handlers/api_gateway_rest_handler.py new file mode 100644 index 00000000000..2f5ad0b94fa --- /dev/null +++ b/tests/e2e/event_handler/handlers/api_gateway_rest_handler.py @@ -0,0 +1,18 @@ +from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response, content_types + +app = APIGatewayRestResolver() + + +@app.get("/todos") +def hello(): + return Response( + status_code=200, + content_type=content_types.TEXT_PLAIN, + body="Hello world", + cookies=["CookieMonster", "MonsterCookie"], + headers={"Foo": ["bar", "zbr"]}, + ) + + +def lambda_handler(event, context): + return app.resolve(event, context) diff --git a/tests/e2e/event_handler/handlers/lambda_function_url_handler.py b/tests/e2e/event_handler/handlers/lambda_function_url_handler.py new file mode 100644 index 00000000000..3fd4b46ea28 --- /dev/null +++ b/tests/e2e/event_handler/handlers/lambda_function_url_handler.py @@ -0,0 +1,18 @@ +from aws_lambda_powertools.event_handler import LambdaFunctionUrlResolver, Response, content_types + +app = LambdaFunctionUrlResolver() + + +@app.get("/todos") +def hello(): + return Response( + status_code=200, + content_type=content_types.TEXT_PLAIN, + body="Hello world", + cookies=["CookieMonster", "MonsterCookie"], + headers={"Foo": ["bar", "zbr"]}, + ) + + +def lambda_handler(event, context): + return app.resolve(event, context) diff --git a/tests/e2e/event_handler/infrastructure.py b/tests/e2e/event_handler/infrastructure.py new file mode 100644 index 00000000000..62421b8aac9 --- /dev/null +++ b/tests/e2e/event_handler/infrastructure.py @@ -0,0 +1,81 @@ +from pathlib import Path +from typing import Dict, Optional + +from aws_cdk import CfnOutput +from aws_cdk import aws_apigateway as apigwv1 +from aws_cdk import aws_apigatewayv2_alpha as apigwv2 +from aws_cdk import aws_apigatewayv2_integrations_alpha as apigwv2integrations +from aws_cdk import aws_ec2 as ec2 +from aws_cdk import aws_elasticloadbalancingv2 as elbv2 +from aws_cdk import aws_elasticloadbalancingv2_targets as targets +from aws_cdk.aws_lambda import Function, FunctionUrlAuthType + +from tests.e2e.utils.infrastructure import BaseInfrastructure + + +class EventHandlerStack(BaseInfrastructure): + FEATURE_NAME = "event-handlers" + + def __init__(self, handlers_dir: Path, feature_name: str = FEATURE_NAME, layer_arn: str = "") -> None: + super().__init__(feature_name, handlers_dir, layer_arn) + + def create_resources(self): + functions = self.create_lambda_functions() + + self._create_alb(function=functions["AlbHandler"]) + self._create_api_gateway_rest(function=functions["ApiGatewayRestHandler"]) + self._create_api_gateway_http(function=functions["ApiGatewayHttpHandler"]) + self._create_lambda_function_url(function=functions["LambdaFunctionUrlHandler"]) + + def _create_alb(self, function: Function): + vpc = ec2.Vpc(self.stack, "EventHandlerVPC", max_azs=2) + + alb = elbv2.ApplicationLoadBalancer(self.stack, "ALB", vpc=vpc, internet_facing=True) + CfnOutput(self.stack, "ALBDnsName", value=alb.load_balancer_dns_name) + + self._create_alb_listener(alb=alb, name="Basic", port=80, function=function) + self._create_alb_listener( + alb=alb, + name="MultiValueHeader", + port=8080, + function=function, + attributes={"lambda.multi_value_headers.enabled": "true"}, + ) + + def _create_alb_listener( + self, + alb: elbv2.ApplicationLoadBalancer, + name: str, + port: int, + function: Function, + attributes: Optional[Dict[str, str]] = None, + ): + listener = alb.add_listener(name, port=port, protocol=elbv2.ApplicationProtocol.HTTP) + target = listener.add_targets(f"ALB{name}Target", targets=[targets.LambdaTarget(function)]) + if attributes is not None: + for key, value in attributes.items(): + target.set_attribute(key, value) + CfnOutput(self.stack, f"ALB{name}ListenerPort", value=str(port)) + + def _create_api_gateway_http(self, function: Function): + apigw = apigwv2.HttpApi(self.stack, "APIGatewayHTTP", create_default_stage=True) + apigw.add_routes( + path="/todos", + methods=[apigwv2.HttpMethod.GET], + integration=apigwv2integrations.HttpLambdaIntegration("TodosIntegration", function), + ) + + CfnOutput(self.stack, "APIGatewayHTTPUrl", value=(apigw.url or "")) + + def _create_api_gateway_rest(self, function: Function): + apigw = apigwv1.RestApi(self.stack, "APIGatewayRest", deploy_options=apigwv1.StageOptions(stage_name="dev")) + + todos = apigw.root.add_resource("todos") + todos.add_method("GET", apigwv1.LambdaIntegration(function, proxy=True)) + + CfnOutput(self.stack, "APIGatewayRestUrl", value=apigw.url) + + def _create_lambda_function_url(self, function: Function): + # Maintenance: move auth to IAM when we create sigv4 builders + function_url = function.add_function_url(auth_type=FunctionUrlAuthType.NONE) + CfnOutput(self.stack, "LambdaFunctionUrl", value=function_url.url) diff --git a/tests/e2e/event_handler/test_header_serializer.py b/tests/e2e/event_handler/test_header_serializer.py new file mode 100644 index 00000000000..2b1d51bfb3d --- /dev/null +++ b/tests/e2e/event_handler/test_header_serializer.py @@ -0,0 +1,141 @@ +import pytest +from requests import Request + +from tests.e2e.utils import data_fetcher + + +@pytest.fixture +def alb_basic_listener_endpoint(infrastructure: dict) -> str: + dns_name = infrastructure.get("ALBDnsName") + port = infrastructure.get("ALBBasicListenerPort", "") + return f"http://{dns_name}:{port}" + + +@pytest.fixture +def alb_multi_value_header_listener_endpoint(infrastructure: dict) -> str: + dns_name = infrastructure.get("ALBDnsName") + port = infrastructure.get("ALBMultiValueHeaderListenerPort", "") + return f"http://{dns_name}:{port}" + + +@pytest.fixture +def apigw_rest_endpoint(infrastructure: dict) -> str: + return infrastructure.get("APIGatewayRestUrl", "") + + +@pytest.fixture +def apigw_http_endpoint(infrastructure: dict) -> str: + return infrastructure.get("APIGatewayHTTPUrl", "") + + +@pytest.fixture +def lambda_function_url_endpoint(infrastructure: dict) -> str: + return infrastructure.get("LambdaFunctionUrl", "") + + +def test_alb_headers_serializer(alb_basic_listener_endpoint): + # GIVEN + url = f"{alb_basic_listener_endpoint}/todos" + + # WHEN + response = data_fetcher.get_http_response(Request(method="GET", url=url)) + + # THEN + assert response.status_code == 200 + assert response.content == b"Hello world" + assert response.headers["content-type"] == "text/plain" + + # Only the last header for key "Foo" should be set + assert response.headers["Foo"] == "zbr" + + # Only the last cookie should be set + assert "MonsterCookie" in response.cookies.keys() + assert "CookieMonster" not in response.cookies.keys() + + +def test_alb_multi_value_headers_serializer(alb_multi_value_header_listener_endpoint): + # GIVEN + url = f"{alb_multi_value_header_listener_endpoint}/todos" + + # WHEN + response = data_fetcher.get_http_response(Request(method="GET", url=url)) + + # THEN + assert response.status_code == 200 + assert response.content == b"Hello world" + assert response.headers["content-type"] == "text/plain" + + # Only the last header for key "Foo" should be set + assert "Foo" in response.headers + foo_headers = [x.strip() for x in response.headers["Foo"].split(",")] + assert sorted(foo_headers) == ["bar", "zbr"] + + # Only the last cookie should be set + assert "MonsterCookie" in response.cookies.keys() + assert "CookieMonster" in response.cookies.keys() + + +def test_api_gateway_rest_headers_serializer(apigw_rest_endpoint): + # GIVEN + url = f"{apigw_rest_endpoint}/todos" + + # WHEN + response = data_fetcher.get_http_response(Request(method="GET", url=url)) + + # THEN + assert response.status_code == 200 + assert response.content == b"Hello world" + assert response.headers["content-type"] == "text/plain" + + # Only the last header for key "Foo" should be set + assert "Foo" in response.headers + foo_headers = [x.strip() for x in response.headers["Foo"].split(",")] + assert sorted(foo_headers) == ["bar", "zbr"] + + # Only the last cookie should be set + assert "MonsterCookie" in response.cookies.keys() + assert "CookieMonster" in response.cookies.keys() + + +def test_api_gateway_http_headers_serializer(apigw_http_endpoint): + # GIVEN + url = f"{apigw_http_endpoint}/todos" + + # WHEN + response = data_fetcher.get_http_response(Request(method="GET", url=url)) + + # THEN + assert response.status_code == 200 + assert response.content == b"Hello world" + assert response.headers["content-type"] == "text/plain" + + # Only the last header for key "Foo" should be set + assert "Foo" in response.headers + foo_headers = [x.strip() for x in response.headers["Foo"].split(",")] + assert sorted(foo_headers) == ["bar", "zbr"] + + # Only the last cookie should be set + assert "MonsterCookie" in response.cookies.keys() + assert "CookieMonster" in response.cookies.keys() + + +def test_lambda_function_url_headers_serializer(lambda_function_url_endpoint): + # GIVEN + url = f"{lambda_function_url_endpoint}todos" # the function url endpoint already has the trailing / + + # WHEN + response = data_fetcher.get_http_response(Request(method="GET", url=url)) + + # THEN + assert response.status_code == 200 + assert response.content == b"Hello world" + assert response.headers["content-type"] == "text/plain" + + # Only the last header for key "Foo" should be set + assert "Foo" in response.headers + foo_headers = [x.strip() for x in response.headers["Foo"].split(",")] + assert sorted(foo_headers) == ["bar", "zbr"] + + # Only the last cookie should be set + assert "MonsterCookie" in response.cookies.keys() + assert "CookieMonster" in response.cookies.keys() diff --git a/tests/e2e/utils/data_fetcher/__init__.py b/tests/e2e/utils/data_fetcher/__init__.py index 43024f9946f..be6909537e5 100644 --- a/tests/e2e/utils/data_fetcher/__init__.py +++ b/tests/e2e/utils/data_fetcher/__init__.py @@ -1,4 +1,4 @@ -from tests.e2e.utils.data_fetcher.common import get_lambda_response +from tests.e2e.utils.data_fetcher.common import get_http_response, get_lambda_response from tests.e2e.utils.data_fetcher.logs import get_logs from tests.e2e.utils.data_fetcher.metrics import get_metrics from tests.e2e.utils.data_fetcher.traces import get_traces diff --git a/tests/e2e/utils/data_fetcher/common.py b/tests/e2e/utils/data_fetcher/common.py index 2de8838dc74..29f97eab2de 100644 --- a/tests/e2e/utils/data_fetcher/common.py +++ b/tests/e2e/utils/data_fetcher/common.py @@ -2,8 +2,12 @@ from typing import Optional, Tuple import boto3 +import requests as requests from mypy_boto3_lambda import LambdaClient from mypy_boto3_lambda.type_defs import InvocationResponseTypeDef +from requests import Request, Response +from requests.exceptions import RequestException +from retry import retry def get_lambda_response( @@ -13,3 +17,11 @@ def get_lambda_response( payload = payload or "" execution_time = datetime.utcnow() return client.invoke(FunctionName=lambda_arn, InvocationType="RequestResponse", Payload=payload), execution_time + + +@retry(RequestException, delay=2, jitter=1.5, tries=5) +def get_http_response(request: Request) -> Response: + session = requests.Session() + result = session.send(request.prepare()) + result.raise_for_status() + return result diff --git a/tests/e2e/utils/infrastructure.py b/tests/e2e/utils/infrastructure.py index 7f232bb063f..47f2d65b7eb 100644 --- a/tests/e2e/utils/infrastructure.py +++ b/tests/e2e/utils/infrastructure.py @@ -15,9 +15,11 @@ from filelock import FileLock from mypy_boto3_cloudformation import CloudFormationClient +from aws_lambda_powertools import PACKAGE_PATH from tests.e2e.utils.asset import Assets PYTHON_RUNTIME_VERSION = f"V{''.join(map(str, sys.version_info[:2]))}" +SOURCE_CODE_ROOT_PATH = PACKAGE_PATH.parent logger = logging.getLogger(__name__) @@ -48,7 +50,7 @@ def __init__(self, feature_name: str, handlers_dir: Path, layer_arn: str = "") - # NOTE: Investigate why cdk.Environment in Stack # changes synthesized asset (no object_key in asset manifest) - self.app = App() + self.app = App(outdir=str(SOURCE_CODE_ROOT_PATH / ".cdk")) self.stack = Stack(self.app, self.stack_name) self.session = boto3.Session() self.cfn: CloudFormationClient = self.session.client("cloudformation") @@ -57,7 +59,7 @@ def __init__(self, feature_name: str, handlers_dir: Path, layer_arn: str = "") - self.account_id = self.session.client("sts").get_caller_identity()["Account"] self.region = self.session.region_name - def create_lambda_functions(self, function_props: Optional[Dict] = None): + def create_lambda_functions(self, function_props: Optional[Dict] = None) -> Dict[str, Function]: """Create Lambda functions available under handlers_dir It creates CloudFormation Outputs for every function found in PascalCase. For example, @@ -69,6 +71,11 @@ def create_lambda_functions(self, function_props: Optional[Dict] = None): function_props: Optional[Dict] Dictionary representing CDK Lambda FunctionProps to override defaults + Returns + ------- + output: Dict[str, Function] + A dict with PascalCased function names and the corresponding CDK Function object + Examples -------- @@ -97,6 +104,8 @@ def create_lambda_functions(self, function_props: Optional[Dict] = None): layer = LayerVersion.from_layer_version_arn(self.stack, "layer-arn", layer_version_arn=self.layer_arn) function_settings_override = function_props or {} + output: Dict[str, Function] = {} + for fn in handlers: fn_name = fn.stem fn_name_pascal_case = fn_name.title().replace("_", "") # basic_handler -> BasicHandler @@ -124,6 +133,10 @@ def create_lambda_functions(self, function_props: Optional[Dict] = None): # CFN Outputs only support hyphen hence pascal case self.add_cfn_output(name=fn_name_pascal_case, value=function.function_name, arn=function.function_arn) + output[fn_name_pascal_case] = function + + return output + def deploy(self) -> Dict[str, str]: """Creates CloudFormation Stack and return stack outputs as dict @@ -287,7 +300,7 @@ def _create_layer(self) -> str: layer_version_name="aws-lambda-powertools-e2e-test", compatible_runtimes=[PythonVersion[PYTHON_RUNTIME_VERSION].value["runtime"]], code=Code.from_asset( - path=".", + path=str(SOURCE_CODE_ROOT_PATH), bundling=BundlingOptions( image=DockerImage.from_build( str(Path(__file__).parent), diff --git a/tests/events/albMultiValueHeadersEvent.json b/tests/events/albMultiValueHeadersEvent.json new file mode 100644 index 00000000000..6b34709605c --- /dev/null +++ b/tests/events/albMultiValueHeadersEvent.json @@ -0,0 +1,35 @@ +{ + "requestContext": { + "elb": { + "targetGroupArn": "arn:aws:elasticloadbalancing:eu-central-1:1234567890:targetgroup/alb-c-Targe-11GDXTPQ7663S/804a67588bfdc10f" + } + }, + "httpMethod": "GET", + "path": "/todos", + "multiValueQueryStringParameters": {}, + "multiValueHeaders": { + "accept": [ + "*/*" + ], + "host": [ + "alb-c-LoadB-14POFKYCLBNSF-1815800096.eu-central-1.elb.amazonaws.com" + ], + "user-agent": [ + "curl/7.79.1" + ], + "x-amzn-trace-id": [ + "Root=1-62fa9327-21cdd4da4c6db451490a5fb7" + ], + "x-forwarded-for": [ + "123.123.123.123" + ], + "x-forwarded-port": [ + "80" + ], + "x-forwarded-proto": [ + "http" + ] + }, + "body": "", + "isBase64Encoded": false +} diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 4b1d7c1ee32..125a0f8c147 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -92,7 +92,26 @@ def get_lambda() -> Response: # THEN process event correctly # AND set the current_event type as APIGatewayProxyEvent assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] + + +def test_api_gateway_v1_cookies(): + # GIVEN a Http API V1 proxy type event + app = APIGatewayRestResolver() + cookie = "CookieMonster" + + @app.get("/my/path") + def get_lambda() -> Response: + assert isinstance(app.current_event, APIGatewayProxyEvent) + return Response(200, content_types.TEXT_PLAIN, "Hello world", cookies=[cookie]) + + # WHEN calling the event handler + result = app(LOAD_GW_EVENT, {}) + + # THEN process event correctly + # AND set the current_event type as APIGatewayProxyEvent + assert result["statusCode"] == 200 + assert result["multiValueHeaders"]["Set-Cookie"] == [cookie] def test_api_gateway(): @@ -110,7 +129,7 @@ def get_lambda() -> Response: # THEN process event correctly # AND set the current_event type as APIGatewayProxyEvent assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.TEXT_HTML + assert result["multiValueHeaders"]["Content-Type"] == [content_types.TEXT_HTML] assert result["body"] == "foo" @@ -132,9 +151,30 @@ def my_path() -> Response: # AND set the current_event type as APIGatewayProxyEventV2 assert result["statusCode"] == 200 assert result["headers"]["Content-Type"] == content_types.TEXT_PLAIN + assert "Cookies" not in result["headers"] assert result["body"] == "tom" +def test_api_gateway_v2_cookies(): + # GIVEN a Http API V2 proxy type event + app = APIGatewayHttpResolver() + cookie = "CookieMonster" + + @app.post("/my/path") + def my_path() -> Response: + assert isinstance(app.current_event, APIGatewayProxyEventV2) + return Response(200, content_types.TEXT_PLAIN, "Hello world", cookies=[cookie]) + + # WHEN calling the event handler + result = app(load_event("apiGatewayProxyV2Event.json"), {}) + + # THEN process event correctly + # AND set the current_event type as APIGatewayProxyEventV2 + assert result["statusCode"] == 200 + assert result["headers"]["Content-Type"] == content_types.TEXT_PLAIN + assert result["cookies"] == [cookie] + + def test_include_rule_matching(): # GIVEN app = ApiGatewayResolver() @@ -149,7 +189,7 @@ def get_lambda(my_id: str, name: str) -> Response: # THEN assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.TEXT_HTML + assert result["multiValueHeaders"]["Content-Type"] == [content_types.TEXT_HTML] assert result["body"] == "path" @@ -200,7 +240,7 @@ def handler(event, context): result = handler(LOAD_GW_EVENT, None) assert result["statusCode"] == 404 # AND cors headers are not returned - assert "Access-Control-Allow-Origin" not in result["headers"] + assert "Access-Control-Allow-Origin" not in result["multiValueHeaders"] def test_cors(): @@ -223,17 +263,17 @@ def handler(event, context): result = handler(LOAD_GW_EVENT, None) # THEN the headers should include cors headers - assert "headers" in result - headers = result["headers"] - assert headers["Content-Type"] == content_types.TEXT_HTML - assert headers["Access-Control-Allow-Origin"] == "*" + assert "multiValueHeaders" in result + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.TEXT_HTML] + assert headers["Access-Control-Allow-Origin"] == ["*"] assert "Access-Control-Allow-Credentials" not in headers - assert headers["Access-Control-Allow-Headers"] == ",".join(sorted(CORSConfig._REQUIRED_HEADERS)) + assert headers["Access-Control-Allow-Headers"] == [",".join(sorted(CORSConfig._REQUIRED_HEADERS))] # THEN for routes without cors flag return no cors headers mock_event = {"path": "/my/request", "httpMethod": "GET"} result = handler(mock_event, None) - assert "Access-Control-Allow-Origin" not in result["headers"] + assert "Access-Control-Allow-Origin" not in result["multiValueHeaders"] def test_cors_preflight_body_is_empty_not_null(): @@ -272,8 +312,8 @@ def handler(event, context): assert isinstance(body, str) decompress = zlib.decompress(base64.b64decode(body), wbits=zlib.MAX_WBITS | 16).decode("UTF-8") assert decompress == expected_value - headers = result["headers"] - assert headers["Content-Encoding"] == "gzip" + headers = result["multiValueHeaders"] + assert headers["Content-Encoding"] == ["gzip"] def test_base64_encode(): @@ -292,8 +332,8 @@ def read_image() -> Response: assert result["isBase64Encoded"] is True body = result["body"] assert isinstance(body, str) - headers = result["headers"] - assert headers["Content-Encoding"] == "gzip" + headers = result["multiValueHeaders"] + assert headers["Content-Encoding"] == ["gzip"] def test_compress_no_accept_encoding(): @@ -348,9 +388,9 @@ def handler(event, context): result = handler({"path": "/success", "httpMethod": "GET"}, None) # THEN return the set Cache-Control - headers = result["headers"] - assert headers["Content-Type"] == content_types.TEXT_HTML - assert headers["Cache-Control"] == "max-age=600" + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.TEXT_HTML] + assert headers["Cache-Control"] == ["max-age=600"] def test_cache_control_non_200(): @@ -369,9 +409,9 @@ def handler(event, context): result = handler({"path": "/fails", "httpMethod": "DELETE"}, None) # THEN return a Cache-Control of "no-cache" - headers = result["headers"] - assert headers["Content-Type"] == content_types.TEXT_HTML - assert headers["Cache-Control"] == "no-cache" + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.TEXT_HTML] + assert headers["Cache-Control"] == ["no-cache"] def test_rest_api(): @@ -388,7 +428,7 @@ def rest_func() -> Dict: # THEN automatically process this as a json rest api response assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected_str = json.dumps(expected_dict, separators=(",", ":"), indent=None, cls=Encoder) assert result["body"] == expected_str @@ -403,7 +443,7 @@ def rest_func() -> Response: status_code=404, content_type="used-if-not-set-in-header", body="Not found", - headers={"Content-Type": "header-content-type-wins", "custom": "value"}, + headers={"Content-Type": ["header-content-type-wins"], "custom": ["value"]}, ) # WHEN calling the event handler @@ -411,8 +451,8 @@ def rest_func() -> Response: # THEN the result can include some additional field control like overriding http headers assert result["statusCode"] == 404 - assert result["headers"]["Content-Type"] == "header-content-type-wins" - assert result["headers"]["custom"] == "value" + assert result["multiValueHeaders"]["Content-Type"] == ["header-content-type-wins"] + assert result["multiValueHeaders"]["custom"] == ["value"] assert result["body"] == "Not found" @@ -441,16 +481,16 @@ def another_one(): result = app(event, None) # THEN routes by default return the custom cors headers - assert "headers" in result - headers = result["headers"] - assert headers["Content-Type"] == content_types.APPLICATION_JSON - assert headers["Access-Control-Allow-Origin"] == cors_config.allow_origin - expected_allows_headers = ",".join(sorted(set(allow_header + cors_config._REQUIRED_HEADERS))) + assert "multiValueHeaders" in result + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.APPLICATION_JSON] + assert headers["Access-Control-Allow-Origin"] == [cors_config.allow_origin] + expected_allows_headers = [",".join(sorted(set(allow_header + cors_config._REQUIRED_HEADERS)))] assert headers["Access-Control-Allow-Headers"] == expected_allows_headers - assert headers["Access-Control-Expose-Headers"] == ",".join(cors_config.expose_headers) - assert headers["Access-Control-Max-Age"] == str(cors_config.max_age) + assert headers["Access-Control-Expose-Headers"] == [",".join(cors_config.expose_headers)] + assert headers["Access-Control-Max-Age"] == [str(cors_config.max_age)] assert "Access-Control-Allow-Credentials" in headers - assert headers["Access-Control-Allow-Credentials"] == "true" + assert headers["Access-Control-Allow-Credentials"] == ["true"] # AND custom cors was set on the app assert isinstance(app._cors, CORSConfig) @@ -459,7 +499,7 @@ def another_one(): # AND routes without cors don't include "Access-Control" headers event = {"path": "/another-one", "httpMethod": "GET"} result = app(event, None) - headers = result["headers"] + headers = result["multiValueHeaders"] assert "Access-Control-Allow-Origin" not in headers @@ -474,7 +514,7 @@ def test_no_content_response(): # THEN return an None body and no Content-Type header assert result["statusCode"] == response.status_code assert result["body"] is None - headers = result["headers"] + headers = result["multiValueHeaders"] assert "Content-Type" not in headers @@ -489,7 +529,7 @@ def test_no_matches_with_cors(): # THEN return a 404 # AND cors headers are returned assert result["statusCode"] == 404 - assert "Access-Control-Allow-Origin" in result["headers"] + assert "Access-Control-Allow-Origin" in result["multiValueHeaders"] assert "Not found" in result["body"] @@ -517,10 +557,10 @@ def post_no_cors(): # AND include Access-Control-Allow-Methods of the cors methods used assert result["statusCode"] == 204 assert result["body"] == "" - headers = result["headers"] + headers = result["multiValueHeaders"] assert "Content-Type" not in headers - assert "Access-Control-Allow-Origin" in result["headers"] - assert headers["Access-Control-Allow-Methods"] == "DELETE,GET,OPTIONS" + assert "Access-Control-Allow-Origin" in result["multiValueHeaders"] + assert headers["Access-Control-Allow-Methods"] == [",".join(sorted(["DELETE", "GET", "OPTIONS"]))] def test_custom_preflight_response(): @@ -535,7 +575,7 @@ def custom_preflight(): status_code=200, content_type=content_types.TEXT_HTML, body="Foo", - headers={"Access-Control-Allow-Methods": "CUSTOM"}, + headers={"Access-Control-Allow-Methods": ["CUSTOM"]}, ) @app.route(method="CUSTOM", rule="/some-call", cors=True) @@ -548,10 +588,10 @@ def custom_method(): # THEN return the custom preflight response assert result["statusCode"] == 200 assert result["body"] == "Foo" - headers = result["headers"] - assert headers["Content-Type"] == content_types.TEXT_HTML - assert "Access-Control-Allow-Origin" in result["headers"] - assert headers["Access-Control-Allow-Methods"] == "CUSTOM" + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.TEXT_HTML] + assert "Access-Control-Allow-Origin" in result["multiValueHeaders"] + assert headers["Access-Control-Allow-Methods"] == ["CUSTOM"] def test_service_error_responses(json_dump): @@ -569,7 +609,7 @@ def bad_request_error(): # THEN return the bad request error response # AND status code equals 400 assert result["statusCode"] == 400 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected = {"statusCode": 400, "message": "Missing required parameter"} assert result["body"] == json_dump(expected) @@ -584,7 +624,7 @@ def unauthorized_error(): # THEN return the unauthorized error response # AND status code equals 401 assert result["statusCode"] == 401 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected = {"statusCode": 401, "message": "Unauthorized"} assert result["body"] == json_dump(expected) @@ -599,7 +639,7 @@ def not_found_error(): # THEN return the not found error response # AND status code equals 404 assert result["statusCode"] == 404 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected = {"statusCode": 404, "message": "Not found"} assert result["body"] == json_dump(expected) @@ -614,7 +654,7 @@ def internal_server_error(): # THEN return the internal server error response # AND status code equals 500 assert result["statusCode"] == 500 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected = {"statusCode": 500, "message": "Internal server error"} assert result["body"] == json_dump(expected) @@ -629,8 +669,8 @@ def service_error(): # THEN return the service error response # AND status code equals 502 assert result["statusCode"] == 502 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON - assert "Access-Control-Allow-Origin" in result["headers"] + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] + assert "Access-Control-Allow-Origin" in result["multiValueHeaders"] expected = {"statusCode": 502, "message": "Something went wrong!"} assert result["body"] == json_dump(expected) @@ -653,8 +693,8 @@ def raises_error(): # AND include the exception traceback in the response assert result["statusCode"] == 500 assert "Traceback (most recent call last)" in result["body"] - headers = result["headers"] - assert headers["Content-Type"] == content_types.TEXT_PLAIN + headers = result["multiValueHeaders"] + assert headers["Content-Type"] == [content_types.TEXT_PLAIN] def test_debug_unhandled_exceptions_debug_off(): @@ -941,7 +981,7 @@ def base(): # THEN process event correctly assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router(): @@ -959,7 +999,7 @@ def foo(): # THEN process event correctly assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router_with_params(): @@ -985,7 +1025,7 @@ def foo(account_id): # THEN process event correctly assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router_with_prefix(): @@ -1004,7 +1044,7 @@ def foo(): # THEN process event correctly assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router_with_prefix_equals_path(): @@ -1024,7 +1064,7 @@ def foo(): # THEN process event correctly assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router_with_different_methods(): @@ -1074,7 +1114,7 @@ def patch_func(): result = app(LOAD_GW_EVENT, None) assert result["statusCode"] == 404 # AND cors headers are not returned - assert "Access-Control-Allow-Origin" not in result["headers"] + assert "Access-Control-Allow-Origin" not in result["multiValueHeaders"] def test_duplicate_routes(): @@ -1133,11 +1173,11 @@ def foo(account_id): # THEN events are processed correctly assert get_result["statusCode"] == 200 - assert get_result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert get_result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] assert post_result["statusCode"] == 200 - assert post_result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert post_result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] assert put_result["statusCode"] == 404 - assert put_result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert put_result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_api_gateway_app_router_access_to_resolver(): @@ -1156,7 +1196,7 @@ def foo(): result = app(LOAD_GW_EVENT, {}) assert result["statusCode"] == 200 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] def test_exception_handler(): @@ -1182,7 +1222,7 @@ def get_lambda() -> Response: # THEN call the exception_handler assert result["statusCode"] == 418 - assert result["headers"]["Content-Type"] == content_types.TEXT_HTML + assert result["multiValueHeaders"]["Content-Type"] == [content_types.TEXT_HTML] assert result["body"] == "Foo!" @@ -1209,7 +1249,7 @@ def get_lambda() -> Response: # THEN call the exception_handler assert result["statusCode"] == 500 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] assert result["body"] == "CUSTOM ERROR FORMAT" @@ -1228,7 +1268,7 @@ def handle_not_found(exc: NotFoundError) -> Response: # THEN call the exception_handler assert result["statusCode"] == 404 - assert result["headers"]["Content-Type"] == content_types.TEXT_PLAIN + assert result["multiValueHeaders"]["Content-Type"] == [content_types.TEXT_PLAIN] assert result["body"] == "I am a teapot!" @@ -1266,7 +1306,7 @@ def get_lambda() -> Response: # THEN call the exception_handler assert result["statusCode"] == 400 - assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON + assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON] expected = {"statusCode": 400, "message": "Bad request"} assert result["body"] == json_dump(expected) diff --git a/tests/functional/event_handler/test_lambda_function_url.py b/tests/functional/event_handler/test_lambda_function_url.py index dc00c535580..ae0a231d46b 100644 --- a/tests/functional/event_handler/test_lambda_function_url.py +++ b/tests/functional/event_handler/test_lambda_function_url.py @@ -21,9 +21,30 @@ def foo(): # AND set the current_event type as LambdaFunctionUrlEvent assert result["statusCode"] == 200 assert result["headers"]["Content-Type"] == content_types.TEXT_HTML + assert "Cookies" not in result["headers"] assert result["body"] == "foo" +def test_lambda_function_url_event_with_cookies(): + # GIVEN a Lambda Function Url type event + app = LambdaFunctionUrlResolver() + cookie = "CookieMonster" + + @app.get("/") + def foo(): + assert isinstance(app.current_event, LambdaFunctionUrlEvent) + assert app.lambda_context == {} + return Response(200, content_types.TEXT_PLAIN, "foo", cookies=[cookie]) + + # WHEN calling the event handler + result = app(load_event("lambdaFunctionUrlEvent.json"), {}) + + # THEN process event correctly + # AND set the current_event type as LambdaFunctionUrlEvent + assert result["statusCode"] == 200 + assert result["cookies"] == [cookie] + + def test_lambda_function_url_no_matches(): # GIVEN a Lambda Function Url type event app = LambdaFunctionUrlResolver() diff --git a/tests/functional/test_headers_serializer.py b/tests/functional/test_headers_serializer.py new file mode 100644 index 00000000000..8a27ce8baa8 --- /dev/null +++ b/tests/functional/test_headers_serializer.py @@ -0,0 +1,147 @@ +from collections import defaultdict + +import pytest + +from aws_lambda_powertools.shared.headers_serializer import ( + HttpApiHeadersSerializer, + MultiValueHeadersSerializer, + SingleValueHeadersSerializer, +) + + +def test_http_api_headers_serializer(): + cookies = ["UUID=12345", "SSID=0xdeadbeef"] + header_values = ["bar", "zbr"] + headers = {"Foo": header_values} + + serializer = HttpApiHeadersSerializer() + payload = serializer.serialize(headers=headers, cookies=cookies) + + assert payload["cookies"] == cookies + assert payload["headers"]["Foo"] == ", ".join(header_values) + + +def test_http_api_headers_serializer_with_empty_values(): + serializer = HttpApiHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=[]) + assert payload == {"headers": {}, "cookies": []} + + +def test_http_api_headers_serializer_with_headers_only(): + content_type = "text/html" + serializer = HttpApiHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": [content_type]}, cookies=[]) + assert payload["headers"]["Content-Type"] == content_type + + +def test_http_api_headers_serializer_with_single_headers_only(): + content_type = "text/html" + serializer = HttpApiHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": content_type}, cookies=[]) + assert payload["headers"]["Content-Type"] == content_type + + +def test_http_api_headers_serializer_with_cookies_only(): + cookies = ["UUID=12345", "SSID=0xdeadbeef"] + serializer = HttpApiHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=cookies) + assert payload["cookies"] == cookies + + +def test_multi_value_headers_serializer(): + cookies = ["UUID=12345", "SSID=0xdeadbeef"] + header_values = ["bar", "zbr"] + headers = {"Foo": header_values} + + serializer = MultiValueHeadersSerializer() + payload = serializer.serialize(headers=headers, cookies=cookies) + + assert payload["multiValueHeaders"]["Set-Cookie"] == cookies + assert payload["multiValueHeaders"]["Foo"] == header_values + + +def test_multi_value_headers_serializer_with_headers_only(): + content_type = "text/html" + serializer = MultiValueHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": [content_type]}, cookies=[]) + assert payload["multiValueHeaders"]["Content-Type"] == [content_type] + + +def test_multi_value_headers_serializer_with_single_headers_only(): + content_type = "text/html" + serializer = MultiValueHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": content_type}, cookies=[]) + assert payload["multiValueHeaders"]["Content-Type"] == [content_type] + + +def test_multi_value_headers_serializer_with_cookies_only(): + cookie = "UUID=12345" + serializer = MultiValueHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=[cookie]) + assert payload["multiValueHeaders"]["Set-Cookie"] == [cookie] + + +def test_multi_value_headers_serializer_with_empty_values(): + serializer = MultiValueHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=[]) + assert payload["multiValueHeaders"] == defaultdict(list) + + +def test_single_value_headers_serializer(): + cookie = "UUID=12345" + content_type = "text/html" + headers = {"Content-Type": [content_type]} + + serializer = SingleValueHeadersSerializer() + payload = serializer.serialize(headers=headers, cookies=[cookie]) + assert payload["headers"]["Content-Type"] == content_type + assert payload["headers"]["Set-Cookie"] == cookie + + +def test_single_value_headers_serializer_with_headers_only(): + content_type = "text/html" + serializer = SingleValueHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": [content_type]}, cookies=[]) + assert payload["headers"]["Content-Type"] == content_type + + +def test_single_value_headers_serializer_with_single_headers_only(): + content_type = "text/html" + serializer = SingleValueHeadersSerializer() + payload = serializer.serialize(headers={"Content-Type": content_type}, cookies=[]) + assert payload["headers"]["Content-Type"] == content_type + + +def test_single_value_headers_serializer_with_cookies_only(): + cookie = "UUID=12345" + serializer = SingleValueHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=[cookie]) + assert payload["headers"] == {"Set-Cookie": cookie} + + +def test_single_value_headers_serializer_with_empty_values(): + serializer = SingleValueHeadersSerializer() + payload = serializer.serialize(headers={}, cookies=[]) + assert payload["headers"] == {} + + +def test_single_value_headers_with_multiple_cookies_warning(): + cookies = ["UUID=12345", "SSID=0xdeadbeef"] + warning_message = "Can't encode more than one cookie in the response. Sending the last cookie only." + serializer = SingleValueHeadersSerializer() + + with pytest.warns(match=warning_message): + payload = serializer.serialize(cookies=cookies, headers={}) + + assert payload["headers"]["Set-Cookie"] == cookies[-1] + + +def test_single_value_headers_with_multiple_header_values_warning(): + headers = {"Foo": ["bar", "zbr"]} + warning_message = "Can't encode more than one header value for the same key." + serializer = SingleValueHeadersSerializer() + + with pytest.warns(match=warning_message): + payload = serializer.serialize(cookies=[], headers=headers) + + assert payload["headers"]["Foo"] == headers["Foo"][-1] From 4f750455be024cdc6e799612ca5173f4bd1f7b0c Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Mon, 29 Aug 2022 18:00:47 +0200 Subject: [PATCH 03/12] docs(homepage): note about v2 version --- .github/workflows/v2_on_push_docs.yml | 35 +++++++++++++++++++++++++++ docs/index.md | 3 +++ 2 files changed, 38 insertions(+) create mode 100644 .github/workflows/v2_on_push_docs.yml diff --git a/.github/workflows/v2_on_push_docs.yml b/.github/workflows/v2_on_push_docs.yml new file mode 100644 index 00000000000..997a00103dd --- /dev/null +++ b/.github/workflows/v2_on_push_docs.yml @@ -0,0 +1,35 @@ +name: Docs v2 + +on: + push: + branches: + - v2 + paths: + - "docs/**" + - "mkdocs.yml" + - "examples/**" + +jobs: + changelog: + permissions: + contents: write + uses: ./.github/workflows/reusable_publish_changelog.yml + + release-docs: + needs: changelog + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable_publish_docs.yml + with: + version: v2 + alias: alpha +# Maintenance: Only necessary in repo migration +# - name: Create redirect from old docs +# run: | +# git checkout gh-pages +# test -f 404.html && echo "Redirect already set" && exit 0 +# git checkout develop -- 404.html +# git add 404.html +# git commit -m "chore: set docs redirect" --no-verify +# git push origin gh-pages -f diff --git a/docs/index.md b/docs/index.md index 95ce2c2a707..97d517bc47f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,6 +5,9 @@ description: AWS Lambda Powertools for Python +???+ danger + This documentation is for v2 that is not yet released. + A suite of utilities for AWS Lambda functions to ease adopting best practices such as tracing, structured logging, custom metrics, idempotency, batching, and more. ???+ note From ed763d68466788e4f6dfe68defc5a9966ff509fa Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Mon, 29 Aug 2022 18:06:17 +0200 Subject: [PATCH 04/12] chore: sync trunk ci with v2 Signed-off-by: heitorlessa --- .github/scripts/comment_on_large_pr.js | 73 +++++++++ .github/workflows/build_changelog.yml | 9 ++ .github/workflows/codeql-analysis.yml | 30 ++-- .github/workflows/on_label_added.yml | 38 +++++ .github/workflows/on_opened_pr.yml | 2 - .github/workflows/on_push_docs.yml | 35 +++++ .github/workflows/on_release_notes.yml | 142 ++++++++++++++++++ .github/workflows/python_build.yml | 7 +- .github/workflows/rebuild_latest_docs.yml | 56 ++----- .github/workflows/record_pr.yml | 2 +- .../workflows/reusable_deploy_layer_stack.yml | 3 + .../workflows/reusable_export_pr_details.yml | 3 + .../workflows/reusable_publish_changelog.yml | 11 +- .github/workflows/reusable_publish_docs.yml | 83 ++++++++++ .github/workflows/run-e2e-tests.yml | 21 ++- 15 files changed, 442 insertions(+), 73 deletions(-) create mode 100644 .github/scripts/comment_on_large_pr.js create mode 100644 .github/workflows/build_changelog.yml create mode 100644 .github/workflows/on_label_added.yml create mode 100644 .github/workflows/on_push_docs.yml create mode 100644 .github/workflows/on_release_notes.yml create mode 100644 .github/workflows/reusable_publish_docs.yml diff --git a/.github/scripts/comment_on_large_pr.js b/.github/scripts/comment_on_large_pr.js new file mode 100644 index 00000000000..c17199faf76 --- /dev/null +++ b/.github/scripts/comment_on_large_pr.js @@ -0,0 +1,73 @@ +const { + PR_NUMBER, + PR_ACTION, + PR_AUTHOR, + IGNORE_AUTHORS, +} = require("./constants") + + +/** + * Notify PR author to split XXL PR in smaller chunks + * + * @param {object} core - core functions instance from @actions/core + * @param {object} gh_client - Pre-authenticated REST client (Octokit) + * @param {string} owner - GitHub Organization + * @param {string} repository - GitHub repository + */ +const notifyAuthor = async ({ + core, + gh_client, + owner, + repository, +}) => { + core.info(`Commenting on PR ${PR_NUMBER}`) + + let msg = `### ⚠️Large PR detected⚠️ + +Please consider breaking into smaller PRs to avoid significant review delays. Ignore if this PR has naturally grown to this size after reviews. + `; + + try { + await gh_client.rest.issues.createComment({ + owner: owner, + repo: repository, + body: msg, + issue_number: PR_NUMBER, + }); + } catch (error) { + core.setFailed("Failed to notify PR author to split large PR"); + console.error(err); + } +} + +module.exports = async ({github, context, core}) => { + if (IGNORE_AUTHORS.includes(PR_AUTHOR)) { + return core.notice("Author in IGNORE_AUTHORS list; skipping...") + } + + if (PR_ACTION != "labeled") { + return core.notice("Only run on PRs labeling actions; skipping") + } + + + /** @type {string[]} */ + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: PR_NUMBER, + }) + + // Schema: https://docs.github.com/en/rest/issues/labels#list-labels-for-an-issue + for (const label of labels) { + core.info(`Label: ${label}`) + if (label.name == "size/XXL") { + await notifyAuthor({ + core: core, + gh_client: github, + owner: context.repo.owner, + repository: context.repo.repo, + }) + break; + } + } +} diff --git a/.github/workflows/build_changelog.yml b/.github/workflows/build_changelog.yml new file mode 100644 index 00000000000..3cd6fffe855 --- /dev/null +++ b/.github/workflows/build_changelog.yml @@ -0,0 +1,9 @@ +# Standalone workflow to update changelog if necessary +name: Build changelog + +on: + workflow_dispatch: + +jobs: + changelog: + uses: ./.github/workflows/reusable_publish_changelog.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index edd7e67bf91..f8a7849e7ea 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,7 +2,7 @@ name: "CodeQL" on: push: - branches: [develop] + branches: [develop, v2] jobs: analyze: @@ -14,23 +14,23 @@ jobs: matrix: # Override automatic language detection by changing the below list # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['python'] + language: ["python"] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/on_label_added.yml b/.github/workflows/on_label_added.yml new file mode 100644 index 00000000000..e9180d8010a --- /dev/null +++ b/.github/workflows/on_label_added.yml @@ -0,0 +1,38 @@ +name: On Label added + +on: + workflow_run: + workflows: ["Record PR details"] + types: + - completed + +jobs: + get_pr_details: + if: ${{ github.event.workflow_run.conclusion == 'success' }} + uses: ./.github/workflows/reusable_export_pr_details.yml + with: + record_pr_workflow_id: ${{ github.event.workflow_run.id }} + workflow_origin: ${{ github.event.repository.full_name }} + secrets: + token: ${{ secrets.GITHUB_TOKEN }} + + split-large-pr: + needs: get_pr_details + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/checkout@v3 + # Maintenance: Persist state per PR as an artifact to avoid spam on label add + - name: "Suggest split large Pull Request" + uses: actions/github-script@v6 + env: + PR_NUMBER: ${{ needs.get_pr_details.outputs.prNumber }} + PR_ACTION: ${{ needs.get_pr_details.outputs.prAction }} + PR_AUTHOR: ${{ needs.get_pr_details.outputs.prAuthor }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const script = require('.github/scripts/comment_on_large_pr.js'); + await script({github, context, core}); diff --git a/.github/workflows/on_opened_pr.yml b/.github/workflows/on_opened_pr.yml index 2663d605325..6c5979c8b80 100644 --- a/.github/workflows/on_opened_pr.yml +++ b/.github/workflows/on_opened_pr.yml @@ -20,8 +20,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: "Debug workflow_run event" - run: echo "${{ github }}" - name: "Ensure related issue is present" uses: actions/github-script@v6 env: diff --git a/.github/workflows/on_push_docs.yml b/.github/workflows/on_push_docs.yml new file mode 100644 index 00000000000..d46879ca6b1 --- /dev/null +++ b/.github/workflows/on_push_docs.yml @@ -0,0 +1,35 @@ +name: Docs + +on: + push: + branches: + - develop + paths: + - "docs/**" + - "mkdocs.yml" + - "examples/**" + +jobs: + changelog: + permissions: + contents: write + uses: ./.github/workflows/reusable_publish_changelog.yml + + release-docs: + needs: changelog + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable_publish_docs.yml + with: + version: develop + alias: stage +# Maintenance: Only necessary in repo migration +# - name: Create redirect from old docs +# run: | +# git checkout gh-pages +# test -f 404.html && echo "Redirect already set" && exit 0 +# git checkout develop -- 404.html +# git add 404.html +# git commit -m "chore: set docs redirect" --no-verify +# git push origin gh-pages -f diff --git a/.github/workflows/on_release_notes.yml b/.github/workflows/on_release_notes.yml new file mode 100644 index 00000000000..2b431defff0 --- /dev/null +++ b/.github/workflows/on_release_notes.yml @@ -0,0 +1,142 @@ +name: Publish to PyPi + +# RELEASE PROCESS +# +# === Manual activities === +# +# 1. Edit the current draft release notes +# 2. If not already set, use `v` as a tag, e.g., v1.26.4, and select develop as target branch +# +# === Automated activities === +# +# 1. Extract release notes tag that was published +# 2. Run tests, linting, security and complexity base line +# 3. Bump package version and generate latest Changelog +# 4. Publish package to PyPi test and prod repository +# 5. Kick off SAR App pipeline to publish latest version with minimal and extra dependencies +# 6. Builds and publish latest changelog from tip of the branch +# 7. Builds a new user guide and API docs with release version; update /latest pointing to newly released version +# 8. Close all issues labeled "pending-release" and notify customers about the release + +# See MAINTAINERS.md "Releasing a new version" for release mechanisms + +env: + BRANCH: develop + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version_to_publish: + description: "Version to be released in PyPi, Docs, and Lambda Layer, e.g. v1.26.4" + default: v1.26.4 + required: true + skip_pypi: + description: "Skip publishing to PyPi as it can't publish more than once. Useful for semi-failed releases" + default: false + type: boolean + required: false + skip_code_quality: + description: "Skip tests, linting, and baseline. Only use if release fail for reasons beyond our control and you need a quick release." + default: false + type: boolean + required: false + +jobs: + release: + environment: release + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + outputs: + RELEASE_VERSION: ${{ steps.release_version.outputs.RELEASE_VERSION }} + env: + RELEASE_TAG_VERSION: ${{ github.event.release.tag_name || inputs.version_to_publish }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install poetry + run: pipx install poetry + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.8" + cache: "poetry" + - name: Set release notes tag + id: release_version + # transform tag format `v> "$GITHUB_ENV" + echo "::set-output name=RELEASE_VERSION::${RELEASE_VERSION}" + - name: Install dependencies + run: make dev + - name: Run all tests, linting and baselines + if: ${{ !inputs.skip_code_quality }} + run: make pr + - name: Bump package version + run: poetry version "${RELEASE_VERSION}" + - name: Build python package and wheel + if: ${{ !inputs.skip_pypi }} + run: poetry build + - name: Upload to PyPi test + if: ${{ !inputs.skip_pypi }} + run: make release-test + env: + PYPI_USERNAME: __token__ + PYPI_TEST_TOKEN: ${{ secrets.PYPI_TEST_TOKEN }} + - name: Upload to PyPi prod + if: ${{ !inputs.skip_pypi }} + run: make release-prod + env: + PYPI_USERNAME: __token__ + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + - name: aws credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-region: eu-west-1 + role-to-assume: ${{ secrets.AWS_SAR_ROLE_ARN }} + - name: publish lambda layer in SAR by triggering the internal codepipeline + run: | + aws ssm put-parameter --name "powertools-python-release-version" --value "$RELEASE_VERSION" --overwrite + aws codepipeline start-pipeline-execution --name ${{ secrets.AWS_SAR_PIPELINE_NAME }} + + changelog: + needs: release + permissions: + contents: write + uses: ./.github/workflows/reusable_publish_changelog.yml + + docs: + needs: [release, changelog] + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable_publish_docs.yml + with: + version: ${{ needs.release.outputs.RELEASE_VERSION }} + alias: latest + detached_mode: true + + post_release: + needs: release + permissions: + contents: read + issues: write + discussions: write + pull-requests: write + runs-on: ubuntu-latest + env: + RELEASE_VERSION: ${{ needs.release.outputs.RELEASE_VERSION }} + steps: + - uses: actions/checkout@v3 + - name: Close issues related to this release + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const post_release = require('.github/scripts/post_release.js') + await post_release({github, context, core}) diff --git a/.github/workflows/python_build.yml b/.github/workflows/python_build.yml index 901c593ebce..29ec0afaad5 100644 --- a/.github/workflows/python_build.yml +++ b/.github/workflows/python_build.yml @@ -10,6 +10,7 @@ on: - "mypy.ini" branches: - develop + - v2 push: paths: - "aws_lambda_powertools/**" @@ -19,6 +20,7 @@ on: - "mypy.ini" branches: - develop + - v2 jobs: build: @@ -28,7 +30,6 @@ jobs: matrix: python-version: [3.7, 3.8, 3.9] env: - OS: ${{ matrix.os }} PYTHON: ${{ matrix.python-version }} steps: - uses: actions/checkout@v3 @@ -55,7 +56,5 @@ jobs: uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # 3.1.0 with: file: ./coverage.xml - # flags: unittests - env_vars: OS,PYTHON + env_vars: PYTHON name: aws-lambda-powertools-python-codecov - # fail_ci_if_error: true # failing more consistently making CI unreliable despite all tests above passing diff --git a/.github/workflows/rebuild_latest_docs.yml b/.github/workflows/rebuild_latest_docs.yml index bd9cffe8feb..eb995d95a12 100644 --- a/.github/workflows/rebuild_latest_docs.yml +++ b/.github/workflows/rebuild_latest_docs.yml @@ -5,14 +5,13 @@ name: Rebuild latest docs # # 1. Trigger "Rebuild latest docs" workflow manually: https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow # 2. Use the latest version released under Releases e.g. v1.22.0 -# 3. Set `Build and publish docs only` field to `true` on: workflow_dispatch: inputs: latest_published_version: description: "Latest PyPi published version to rebuild latest docs for, e.g. v1.26.7" - default: "v1.26.7" + default: "v1.28.0" required: true jobs: @@ -21,49 +20,12 @@ jobs: contents: write uses: ./.github/workflows/reusable_publish_changelog.yml - release: + release-docs: needs: changelog - # Force Github action to run only a single job at a time (based on the group name) - # This is to prevent "race-condition" in publishing a new version of doc to `gh-pages` - concurrency: - group: on-docs-rebuild - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Install poetry - run: pipx install poetry - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.8" - cache: "poetry" - - name: Set release notes tag - run: | - RELEASE_TAG_VERSION=${{ github.event.inputs.latest_published_version }} - echo "RELEASE_TAG_VERSION=${RELEASE_TAG_VERSION:1}" >> $GITHUB_ENV - - name: Install dependencies - run: make dev - - name: Setup doc deploy - run: | - git config --global user.name Docs deploy - git config --global user.email aws-devax-open-source@amazon.com - - name: Build docs website and API reference - run: | - make release-docs VERSION=${RELEASE_TAG_VERSION} ALIAS="latest" - poetry run mike set-default --push latest - - name: Release API docs to release version - uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./api - keep_files: true - destination_dir: ${{ env.RELEASE_TAG_VERSION }}/api - - name: Release API docs to latest - uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./api - keep_files: true - destination_dir: latest/api + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable_publish_docs.yml + with: + version: ${{ inputs.latest_published_version }} + alias: latest diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml index 44f445a70ac..b1638ad8865 100644 --- a/.github/workflows/record_pr.yml +++ b/.github/workflows/record_pr.yml @@ -2,7 +2,7 @@ name: Record PR details on: pull_request: - types: [opened, edited, closed] + types: [opened, edited, closed, labeled] jobs: record_pr: diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index e1190e19873..20d69b9c814 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -8,12 +8,15 @@ on: workflow_call: inputs: stage: + description: "Deployment stage (BETA, PROD)" required: true type: string artefact-name: + description: "CDK Layer Artefact name to download" required: true type: string environment: + description: "GitHub Environment to use for encrypted secrets" required: true type: string diff --git a/.github/workflows/reusable_export_pr_details.yml b/.github/workflows/reusable_export_pr_details.yml index 86c3e7d645e..ec168b95f20 100644 --- a/.github/workflows/reusable_export_pr_details.yml +++ b/.github/workflows/reusable_export_pr_details.yml @@ -4,13 +4,16 @@ on: workflow_call: inputs: record_pr_workflow_id: + description: "Record PR workflow execution ID to download PR details" required: true type: number workflow_origin: # see https://github.com/awslabs/aws-lambda-powertools-python/issues/1349 + description: "Repository full name for runner integrity" required: true type: string secrets: token: + description: "GitHub Actions temporary and scoped token" required: true # Map the workflow outputs to job outputs outputs: diff --git a/.github/workflows/reusable_publish_changelog.yml b/.github/workflows/reusable_publish_changelog.yml index 9bd0959d1c8..30e49b98ae5 100644 --- a/.github/workflows/reusable_publish_changelog.yml +++ b/.github/workflows/reusable_publish_changelog.yml @@ -6,6 +6,9 @@ on: permissions: contents: write +env: + BRANCH: develop + jobs: publish_changelog: # Force Github action to run only a single job at a time (based on the group name) @@ -23,11 +26,15 @@ jobs: git config user.name "Release bot" git config user.email "aws-devax-open-source@amazon.com" git config pull.rebase true - git pull --rebase + git config remote.origin.url >&- || git remote add origin https://github.com/"${origin}" # Git Detached mode (release notes) doesn't have origin + git pull origin "${BRANCH}" - name: "Generate latest changelog" run: make changelog - name: Update Changelog in trunk run: | + HAS_CHANGE=$(git status --porcelain) + test -z "${HAS_CHANGE}" && echo "Nothing to update" && exit 0 git add CHANGELOG.md git commit -m "update changelog with latest changes" - git push origin HEAD:refs/heads/develop + git pull origin "${BRANCH}" # prevents concurrent branch update failing push + git push origin HEAD:refs/heads/"${BRANCH}" diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml new file mode 100644 index 00000000000..a157783abf4 --- /dev/null +++ b/.github/workflows/reusable_publish_docs.yml @@ -0,0 +1,83 @@ +name: Reusable publish documentation + +env: + BRANCH: develop + ORIGIN: awslabs/aws-lambda-powertools-python + +on: + workflow_call: + inputs: + version: + description: "Version to build and publish docs (v1.28.0, develop)" + required: true + type: string + alias: + description: "Alias to associate version (latest, stage)" + required: true + type: string + detached_mode: + description: "Whether it's running in git detached mode to ensure git is sync'd" + required: false + default: false + type: boolean + +permissions: + contents: write + pages: write + +jobs: + publish_docs: + # Force Github action to run only a single job at a time (based on the group name) + # This is to prevent "race-condition" in publishing a new version of doc to `gh-pages` + concurrency: + group: on-docs-rebuild + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install poetry + run: pipx install poetry + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.8" + cache: "poetry" + - name: Install dependencies + run: make dev + - name: Git client setup + run: | + git config --global user.name Docs deploy + git config --global user.email aws-devax-open-source@amazon.com + - name: Git refresh tip (detached mode) + # Git Detached mode (release notes) doesn't have origin + if: ${{ inputs.detached_mode }} + run: | + git config pull.rebase true + git config remote.origin.url >&- || git remote add origin https://github.com/"$ORIGIN" + git pull origin "$BRANCH" + - name: Build docs website and API reference + env: + VERSION: ${{ inputs.version }} + ALIAS: ${{ inputs.alias }} + run: | + make release-docs VERSION="$VERSION" ALIAS="$ALIAS" + poetry run mike set-default --push latest + # Maintenance: Migrate to new gh-pages action + - name: Release API docs + uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 + env: + VERSION: ${{ inputs.version }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./api + keep_files: true + destination_dir: ${{ env.VERSION }}/api + - name: Release API docs to latest + if: ${{ inputs.alias == 'latest' }} + uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./api + keep_files: true + destination_dir: latest/api diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index a020410823c..8bea436f208 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -1,9 +1,24 @@ -name: run-e2e-tests +name: Run end-to-end tests + on: workflow_dispatch: + + push: + branches: [develop, v2] + paths: + - "aws_lambda_powertools/**" + - "tests/e2e/**" + - "pyproject.toml" + - "poetry.lock" + - "mypy.ini" + - "parallel_run_e2e.py" + +# Maintenance: Add support for triggering on `run-e2e` label +# and enforce repo origin to prevent abuse + env: AWS_DEFAULT_REGION: us-east-1 - E2E_TESTS_PATH: tests/e2e/ + jobs: run: runs-on: ubuntu-latest @@ -12,7 +27,9 @@ jobs: contents: read strategy: matrix: + # Maintenance: disabled until we discover concurrency lock issue with multiple versions and tmp version: ["3.7", "3.8", "3.9"] + # version: ["3.7"] steps: - name: "Checkout" uses: actions/checkout@v3 From a6526ff83d7864d77dd92bdf6d5486c852f63f4e Mon Sep 17 00:00:00 2001 From: heitorlessa Date: Mon, 29 Aug 2022 18:11:45 +0200 Subject: [PATCH 05/12] chore(ci): create adhoc docs workflow for v2 --- .github/workflows/v2_rebuild_latest_docs.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/v2_rebuild_latest_docs.yml diff --git a/.github/workflows/v2_rebuild_latest_docs.yml b/.github/workflows/v2_rebuild_latest_docs.yml new file mode 100644 index 00000000000..6d833cc3fef --- /dev/null +++ b/.github/workflows/v2_rebuild_latest_docs.yml @@ -0,0 +1,14 @@ +name: V2 Rebuild latest docs + +on: + workflow_dispatch: + +jobs: + release-docs: + permissions: + contents: write + pages: write + uses: ./.github/workflows/reusable_publish_docs.yml + with: + version: v2 + alias: alpha From 9715cfe3499b5796a2e44501e3d7c45c30382089 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 31 Aug 2022 00:55:28 +0100 Subject: [PATCH 06/12] feat(capture_method): adding more tests to e2e tests --- .../e2e/tracer/handlers/same_function_name.py | 26 +++++++++++ tests/e2e/tracer/test_tracer.py | 43 +++++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 tests/e2e/tracer/handlers/same_function_name.py diff --git a/tests/e2e/tracer/handlers/same_function_name.py b/tests/e2e/tracer/handlers/same_function_name.py new file mode 100644 index 00000000000..2c66c0b3e15 --- /dev/null +++ b/tests/e2e/tracer/handlers/same_function_name.py @@ -0,0 +1,26 @@ +from uuid import uuid4 + +from aws_lambda_powertools import Tracer +from aws_lambda_powertools.utilities.typing import LambdaContext + +tracer = Tracer() + + +class Comments: + @tracer.capture_method + def get_all(self): + return [{"id": f"{uuid4()}", "completed": False} for _ in range(5)] + + +class Todos: + @tracer.capture_method + def get_all(self): + return [{"id": f"{uuid4()}", "completed": False} for _ in range(5)] + + +def lambda_handler(event: dict, context: LambdaContext): + + todos = Todos() + comments = Comments() + + return {"todos": todos.get_all(), "comments": comments.get_all()} diff --git a/tests/e2e/tracer/test_tracer.py b/tests/e2e/tracer/test_tracer.py index 06dde811ef1..d5fe7b26582 100644 --- a/tests/e2e/tracer/test_tracer.py +++ b/tests/e2e/tracer/test_tracer.py @@ -15,6 +15,16 @@ def basic_handler_fn(infrastructure: dict) -> str: return infrastructure.get("BasicHandler", "") +@pytest.fixture +def same_function_name_fn(infrastructure: dict) -> str: + return infrastructure.get("SameFunctionName", "") + + +@pytest.fixture +def same_function_name_arn(infrastructure: dict) -> str: + return infrastructure.get("SameFunctionNameArn", "") + + @pytest.fixture def async_fn_arn(infrastructure: dict) -> str: return infrastructure.get("AsyncCaptureArn", "") @@ -31,9 +41,9 @@ def test_lambda_handler_trace_is_visible(basic_handler_fn_arn: str, basic_handle handler_subsegment = f"## {handler_name}" handler_metadata_key = f"{handler_name} response" - method_name = basic_handler.get_todos.__name__ + method_name = f"basic_handler.{basic_handler.get_todos.__name__}" method_subsegment = f"## {method_name}" - handler_metadata_key = f"{method_name} response" + method_metadata_key = f"{method_name} response" trace_query = data_builder.build_trace_default_query(function_name=basic_handler_fn) @@ -46,14 +56,39 @@ def test_lambda_handler_trace_is_visible(basic_handler_fn_arn: str, basic_handle assert len(trace.get_annotation(key="ColdStart", value=True)) == 1 assert len(trace.get_metadata(key=handler_metadata_key, namespace=TracerStack.SERVICE_NAME)) == 2 - assert len(trace.get_metadata(key=handler_metadata_key, namespace=TracerStack.SERVICE_NAME)) == 2 + assert len(trace.get_metadata(key=method_metadata_key, namespace=TracerStack.SERVICE_NAME)) == 2 assert len(trace.get_subsegment(name=handler_subsegment)) == 2 assert len(trace.get_subsegment(name=method_subsegment)) == 2 +def test_lambda_handler_trace_multiple_functions_same_name(same_function_name_arn: str, same_function_name_fn: str): + # GIVEN + method_name_1 = "same_function_name.Todos.get_all" + method_subsegment_1 = f"## {method_name_1}" + method_metadata_key_1 = f"{method_name_1} response" + + method_name_2 = "same_function_name.Comments.get_all" + method_subsegment_2 = f"## {method_name_2}" + method_metadata_key_2 = f"{method_name_2} response" + + trace_query = data_builder.build_trace_default_query(function_name=same_function_name_fn) + + # WHEN + _, execution_time = data_fetcher.get_lambda_response(lambda_arn=same_function_name_arn) + data_fetcher.get_lambda_response(lambda_arn=same_function_name_arn) + + # THEN + trace = data_fetcher.get_traces(start_date=execution_time, filter_expression=trace_query) + + assert len(trace.get_metadata(key=method_metadata_key_1, namespace=TracerStack.SERVICE_NAME)) == 1 + assert len(trace.get_metadata(key=method_metadata_key_2, namespace=TracerStack.SERVICE_NAME)) == 1 + assert len(trace.get_subsegment(name=method_subsegment_1)) == 1 + assert len(trace.get_subsegment(name=method_subsegment_2)) == 1 + + def test_async_trace_is_visible(async_fn_arn: str, async_fn: str): # GIVEN - async_fn_name = async_capture.async_get_users.__name__ + async_fn_name = f"async_capture.{async_capture.async_get_users.__name__}" async_fn_name_subsegment = f"## {async_fn_name}" async_fn_name_metadata_key = f"{async_fn_name} response" From 3b444ae9d599aa961bdc1d806392f38564cf7923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Fonseca?= Date: Wed, 31 Aug 2022 10:26:49 +0200 Subject: [PATCH 07/12] fix(event_handler): fix bug with previous array implementation --- aws_lambda_powertools/event_handler/api_gateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 11adcfc2ed6..2d315fcc434 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -206,7 +206,7 @@ def _add_cache_control(self, cache_control: str): def _compress(self): """Compress the response body, but only if `Accept-Encoding` headers includes gzip.""" - self.response.headers["Content-Encoding"].append("gzip") + self.response.headers["Content-Encoding"] = "gzip" if isinstance(self.response.body, str): logger.debug("Converting string response to bytes before compressing it") self.response.body = bytes(self.response.body, "utf-8") From 6a23e8384d6633c773d7da59d3354dc7b44dc403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Fonseca?= Date: Wed, 31 Aug 2022 10:55:09 +0200 Subject: [PATCH 08/12] chore(bandit): update baseline --- bandit.baseline | 1871 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 1694 insertions(+), 177 deletions(-) diff --git a/bandit.baseline b/bandit.baseline index 2421c4f1e24..144682ffccb 100644 --- a/bandit.baseline +++ b/bandit.baseline @@ -1,226 +1,1743 @@ { "errors": [], - "generated_at": "2020-05-12T08:59:59Z", + "generated_at": "2022-08-31T08:51:10Z", "metrics": { "_totals": { - "CONFIDENCE.HIGH": 1.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 1.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 1375, - "nosec": 0 + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 11903, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 6, - "nosec": 0 - }, - "aws_lambda_powertools/helper/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 2, - "nosec": 0 - }, - "aws_lambda_powertools/helper/models.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 108, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 9, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 23, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/api_gateway.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 645, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/appsync.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 140, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/content_types.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 3, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/cookies.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 58, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 30, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/event_handler/lambda_function_url.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 40, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/exceptions/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 3, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/logging/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 5, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 4, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/logging/correlation_paths.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 9, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/logging/exceptions.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, "loc": 2, - "nosec": 0 + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/logging/filters.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 12, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/logging/formatter.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 220, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/logging/lambda_context.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 47, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/logging/logger.py": { - "CONFIDENCE.HIGH": 1.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 1.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 375, - "nosec": 0 + "CONFIDENCE.HIGH": 1, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 1, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 366, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/logging/utils.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 58, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/metrics/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 15, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/metrics/base.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 162, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 241, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/metrics/exceptions.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 12, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 9, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/metrics/metric.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 90, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 95, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/metrics/metrics.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 82, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 170, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/middleware_factory/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, "loc": 3, - "nosec": 0 + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/middleware_factory/exceptions.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 3, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 2, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/middleware_factory/factory.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 103, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 106, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/package_logger.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 5, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/cache_dict.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/constants.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 24, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/functions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 46, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/headers_serializer.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 85, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/json_encoder.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 13, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/lazy_import.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 24, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/shared/types.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 3, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/tracing/__init__.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, - "loc": 6, - "nosec": 0 + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 5, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/tracing/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 117, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/tracing/extensions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 11, + "nosec": 0, + "skipped_tests": 0 }, "aws_lambda_powertools/tracing/tracer.py": { - "CONFIDENCE.HIGH": 0.0, - "CONFIDENCE.LOW": 0.0, - "CONFIDENCE.MEDIUM": 0.0, - "CONFIDENCE.UNDEFINED": 0.0, - "SEVERITY.HIGH": 0.0, - "SEVERITY.LOW": 0.0, - "SEVERITY.MEDIUM": 0.0, - "SEVERITY.UNDEFINED": 0.0, + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 641, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 1, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/batch/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 24, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/batch/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 333, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/batch/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/batch/sqs.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 204, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 36, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/active_mq_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 100, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/alb_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 32, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 439, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 203, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/appsync/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/appsync/scalar_types_utils.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 73, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 89, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 178, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 77, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 185, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 624, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/common.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 316, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 128, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 237, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/event_bridge_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 53, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/event_source.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 31, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 77, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/lambda_function_url_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 12, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 93, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/s3_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 143, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/s3_object_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 256, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/ses_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 202, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/sns_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 91, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/data_classes/sqs_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 111, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/appconfig.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 92, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 50, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 8, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/feature_flags.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 247, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/feature_flags/schema.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 216, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 7, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 177, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/config.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 48, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 35, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/idempotency.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 128, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/persistence/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 0, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/persistence/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, "loc": 401, - "nosec": 0 + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 201, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/jmespath_utils/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 56, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/jmespath_utils/envelopes.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 8, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 23, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/appconfig.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 151, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 272, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/dynamodb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 178, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 7, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/secrets.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 129, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parameters/ssm.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 277, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 17, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 23, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/apigw.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 42, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 32, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 34, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/kinesis.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 35, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 25, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/sns.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 59, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/envelopes/sqs.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 30, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 4, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 100, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/alb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/apigw.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 77, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/apigwv2.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 55, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/cloudwatch.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 33, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/dynamodb.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 26, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/event_bridge.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 14, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/kinesis.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 31, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/lambda_function_url.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 12, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/s3.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 49, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/s3_object_event.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 40, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/ses.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 52, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/sns.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 36, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/models/sqs.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 32, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/parser.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 128, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/pydantic.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 1, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/parser/types.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 11, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/typing/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 5, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/typing/lambda_client_context.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 18, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 22, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 12, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/typing/lambda_context.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 64, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/validation/__init__.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 12, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/validation/base.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 39, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/validation/envelopes.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 9, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/validation/exceptions.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 53, + "nosec": 0, + "skipped_tests": 0 + }, + "aws_lambda_powertools/utilities/validation/validator.py": { + "CONFIDENCE.HIGH": 0, + "CONFIDENCE.LOW": 0, + "CONFIDENCE.MEDIUM": 0, + "CONFIDENCE.UNDEFINED": 0, + "SEVERITY.HIGH": 0, + "SEVERITY.LOW": 0, + "SEVERITY.MEDIUM": 0, + "SEVERITY.UNDEFINED": 0, + "loc": 168, + "nosec": 0, + "skipped_tests": 0 } }, "results": [ { - "code": "369 try:\n370 if self.sampling_rate and random.random() <= float(self.sampling_rate):\n371 logger.debug(\"Setting log level to Debug due to sampling rate\")\n", + "code": "259 try:\n260 if self.sampling_rate and random.random() <= float(self.sampling_rate):\n261 logger.debug(\"Setting log level to Debug due to sampling rate\")\n", + "col_offset": 38, "filename": "aws_lambda_powertools/logging/logger.py", "issue_confidence": "HIGH", + "issue_cwe": { + "id": 330, + "link": "https://cwe.mitre.org/data/definitions/330.html" + }, "issue_severity": "LOW", "issue_text": "Standard pseudo-random generators are not suitable for security/cryptographic purposes.", - "line_number": 370, + "line_number": 260, "line_range": [ - 370 + 260 ], - "more_info": "https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html#b311-random", + "more_info": "https://bandit.readthedocs.io/en/1.7.4/blacklists/blacklist_calls.html#b311-random", "test_id": "B311", "test_name": "blacklist" } ] -} +} \ No newline at end of file From 19de9ddd7a4fb76218a1516a777c17604da54be4 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Mon, 5 Sep 2022 21:56:55 +0100 Subject: [PATCH 09/12] feat(capture_method): fixing poetry.lock dependency --- poetry.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 265e7beec3f..8c8ff2f1821 100644 --- a/poetry.lock +++ b/poetry.lock @@ -29,8 +29,6 @@ optional = false python-versions = "~=3.7" [package.dependencies] -aws-cdk-lib = ">=2.38.1,<3.0.0" -"aws-cdk.aws-apigatewayv2-alpha" = "2.38.1.a0" constructs = ">=10.0.0,<11.0.0" jsii = ">=1.65.1,<2.0.0" publication = ">=0.0.3" From 9513133cc986e3f52553aae5d683b86b0e810dd7 Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Tue, 6 Sep 2022 18:21:12 +0100 Subject: [PATCH 10/12] feat(capture_method): addressing PR feedback --- aws_lambda_powertools/tracing/tracer.py | 3 +- .../e2e/tracer/handlers/same_function_name.py | 14 +++++++-- tests/e2e/tracer/test_tracer.py | 21 +++++++------ tests/unit/test_tracing.py | 30 +++++++++++-------- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/aws_lambda_powertools/tracing/tracer.py b/aws_lambda_powertools/tracing/tracer.py index 25f5ca17c3d..d889f22c174 100644 --- a/aws_lambda_powertools/tracing/tracer.py +++ b/aws_lambda_powertools/tracing/tracer.py @@ -354,7 +354,8 @@ def capture_method( """Decorator to create subsegment for arbitrary functions It also captures both response and exceptions as metadata - and creates a subsegment named `## ` + and creates a subsegment named `## ` + # see here: [Qualified name for classes and functions](https://peps.python.org/pep-3155/) When running [async functions concurrently](https://docs.python.org/3/library/asyncio-task.html#id6), methods may impact each others subsegment, and can trigger diff --git a/tests/e2e/tracer/handlers/same_function_name.py b/tests/e2e/tracer/handlers/same_function_name.py index 2c66c0b3e15..be080e4336f 100644 --- a/tests/e2e/tracer/handlers/same_function_name.py +++ b/tests/e2e/tracer/handlers/same_function_name.py @@ -1,3 +1,4 @@ +from abc import ABC, abstractmethod from uuid import uuid4 from aws_lambda_powertools import Tracer @@ -6,13 +7,22 @@ tracer = Tracer() -class Comments: +class MainAbstractClass(ABC): + def __init__(self): + super().__init__() + + @abstractmethod + def get_all(self): + raise NotImplementedError + + +class Comments(MainAbstractClass): @tracer.capture_method def get_all(self): return [{"id": f"{uuid4()}", "completed": False} for _ in range(5)] -class Todos: +class Todos(MainAbstractClass): @tracer.capture_method def get_all(self): return [{"id": f"{uuid4()}", "completed": False} for _ in range(5)] diff --git a/tests/e2e/tracer/test_tracer.py b/tests/e2e/tracer/test_tracer.py index d5fe7b26582..de25bc02ebf 100644 --- a/tests/e2e/tracer/test_tracer.py +++ b/tests/e2e/tracer/test_tracer.py @@ -63,27 +63,26 @@ def test_lambda_handler_trace_is_visible(basic_handler_fn_arn: str, basic_handle def test_lambda_handler_trace_multiple_functions_same_name(same_function_name_arn: str, same_function_name_fn: str): # GIVEN - method_name_1 = "same_function_name.Todos.get_all" - method_subsegment_1 = f"## {method_name_1}" - method_metadata_key_1 = f"{method_name_1} response" + method_name_todos = "same_function_name.Todos.get_all" + method_subsegment_todos = f"## {method_name_todos}" + method_metadata_key_todos = f"{method_name_todos} response" - method_name_2 = "same_function_name.Comments.get_all" - method_subsegment_2 = f"## {method_name_2}" - method_metadata_key_2 = f"{method_name_2} response" + method_name_comments = "same_function_name.Comments.get_all" + method_subsegment_comments = f"## {method_name_comments}" + method_metadata_key_comments = f"{method_name_comments} response" trace_query = data_builder.build_trace_default_query(function_name=same_function_name_fn) # WHEN _, execution_time = data_fetcher.get_lambda_response(lambda_arn=same_function_name_arn) - data_fetcher.get_lambda_response(lambda_arn=same_function_name_arn) # THEN trace = data_fetcher.get_traces(start_date=execution_time, filter_expression=trace_query) - assert len(trace.get_metadata(key=method_metadata_key_1, namespace=TracerStack.SERVICE_NAME)) == 1 - assert len(trace.get_metadata(key=method_metadata_key_2, namespace=TracerStack.SERVICE_NAME)) == 1 - assert len(trace.get_subsegment(name=method_subsegment_1)) == 1 - assert len(trace.get_subsegment(name=method_subsegment_2)) == 1 + assert len(trace.get_metadata(key=method_metadata_key_todos, namespace=TracerStack.SERVICE_NAME)) == 1 + assert len(trace.get_metadata(key=method_metadata_key_comments, namespace=TracerStack.SERVICE_NAME)) == 1 + assert len(trace.get_subsegment(name=method_subsegment_todos)) == 1 + assert len(trace.get_subsegment(name=method_subsegment_comments)) == 1 def test_async_trace_is_visible(async_fn_arn: str, async_fn: str): diff --git a/tests/unit/test_tracing.py b/tests/unit/test_tracing.py index ca3be502074..b738b0506eb 100644 --- a/tests/unit/test_tracing.py +++ b/tests/unit/test_tracing.py @@ -10,6 +10,8 @@ # Maintenance: This should move to Functional tests and use Fake over mocks. +__MODULE_PREFIX__ = "unit.test_tracing" + @pytest.fixture def dummy_response(): @@ -126,10 +128,12 @@ def greeting(name, message): # and use service name as a metadata namespace assert in_subsegment_mock.in_subsegment.call_count == 1 assert in_subsegment_mock.in_subsegment.call_args == mocker.call( - name="## unit.test_tracing.test_tracer_method..greeting" + name=f"## {__MODULE_PREFIX__}.test_tracer_method..greeting" ) assert in_subsegment_mock.put_metadata.call_args == mocker.call( - key="unit.test_tracing.test_tracer_method..greeting response", value=dummy_response, namespace="booking" + key=f"{__MODULE_PREFIX__}.test_tracer_method..greeting response", + value=dummy_response, + namespace="booking", ) @@ -257,7 +261,7 @@ def greeting(name, message): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == "unit.test_tracing.test_tracer_method_exception_metadata..greeting error" + == f"{__MODULE_PREFIX__}.test_tracer_method_exception_metadata..greeting error" ) assert put_metadata_mock_args["namespace"] == "booking" @@ -311,20 +315,20 @@ async def greeting(name, message): # THEN we should add metadata for each response like we would for a sync decorated method assert in_subsegment_mock.in_subsegment.call_count == 2 assert in_subsegment_greeting_call_args == mocker.call( - name="## unit.test_tracing.test_tracer_method_nested_async..greeting" + name=f"## {__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting" ) assert in_subsegment_greeting2_call_args == mocker.call( - name="## unit.test_tracing.test_tracer_method_nested_async..greeting_2" + name=f"## {__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting_2" ) assert in_subsegment_mock.put_metadata.call_count == 2 assert put_metadata_greeting2_call_args == mocker.call( - key="unit.test_tracing.test_tracer_method_nested_async..greeting_2 response", + key=f"{__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting_2 response", value=dummy_response, namespace="booking", ) assert put_metadata_greeting_call_args == mocker.call( - key="unit.test_tracing.test_tracer_method_nested_async..greeting response", + key=f"{__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting response", value=dummy_response, namespace="booking", ) @@ -370,7 +374,7 @@ async def greeting(name, message): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == "unit.test_tracing.test_tracer_method_exception_metadata_async..greeting error" + == f"{__MODULE_PREFIX__}.test_tracer_method_exception_metadata_async..greeting error" ) assert put_metadata_mock_args["namespace"] == "booking" @@ -404,7 +408,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert yield_function_trace == mocker.call( - name="## unit.test_tracing.test_tracer_yield_from_context_manager..yield_with_capture" + name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_context_manager..yield_with_capture" ) assert "test result" in result @@ -431,7 +435,7 @@ def yield_with_capture(): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == "unit.test_tracing.test_tracer_yield_from_context_manager_exception_metadata..yield_with_capture error" # noqa E501 + == f"{__MODULE_PREFIX__}.test_tracer_yield_from_context_manager_exception_metadata..yield_with_capture error" # noqa E501 ) assert isinstance(put_metadata_mock_args["value"], ValueError) assert put_metadata_mock_args["namespace"] == "booking" @@ -475,7 +479,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert yield_function_trace == mocker.call( - name="## unit.test_tracing.test_tracer_yield_from_nested_context_manager..yield_with_capture" + name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_nested_context_manager..yield_with_capture" ) assert "test result" in result @@ -507,7 +511,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert generator_fn_trace == mocker.call( - name="## unit.test_tracing.test_tracer_yield_from_generator..generator_fn" + name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_generator..generator_fn" ) assert "test result" in result @@ -533,7 +537,7 @@ def generator_fn(): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == "unit.test_tracing.test_tracer_yield_from_generator_exception_metadata..generator_fn error" + == f"{__MODULE_PREFIX__}.test_tracer_yield_from_generator_exception_metadata..generator_fn error" ) assert put_metadata_mock_args["namespace"] == "booking" assert isinstance(put_metadata_mock_args["value"], ValueError) From 69ed3d8dd1b55e685d40706b0c73be1ece68eb7c Mon Sep 17 00:00:00 2001 From: Leandro Damascena Date: Wed, 7 Sep 2022 10:05:30 +0100 Subject: [PATCH 11/12] feat(capture_method): small fixes --- aws_lambda_powertools/tracing/tracer.py | 1 + docs/media/tracer_utility_showcase.png | Bin 131394 -> 99807 bytes .../e2e/tracer/handlers/same_function_name.py | 3 --- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/aws_lambda_powertools/tracing/tracer.py b/aws_lambda_powertools/tracing/tracer.py index d889f22c174..7053497ae6d 100644 --- a/aws_lambda_powertools/tracing/tracer.py +++ b/aws_lambda_powertools/tracing/tracer.py @@ -509,6 +509,7 @@ async def async_tasks(): functools.partial(self.capture_method, capture_response=capture_response, capture_error=capture_error), ) + # Example: app.ClassA.get_all # noqa E800 method_name = f"{method.__module__}.{method.__qualname__}" capture_response = resolve_truthy_env_var_choice( diff --git a/docs/media/tracer_utility_showcase.png b/docs/media/tracer_utility_showcase.png index 55d7d5d0bf81135fda888b74a2ebbd983d9f9570..b3d3568a01c3ac10268e312dcde6c2a7aade9613 100644 GIT binary patch literal 99807 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 Date: Wed, 7 Sep 2022 22:54:15 +0100 Subject: [PATCH 12/12] feat(capture_method): renaming constant --- tests/unit/test_tracing.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_tracing.py b/tests/unit/test_tracing.py index b738b0506eb..a40301a44c2 100644 --- a/tests/unit/test_tracing.py +++ b/tests/unit/test_tracing.py @@ -10,7 +10,7 @@ # Maintenance: This should move to Functional tests and use Fake over mocks. -__MODULE_PREFIX__ = "unit.test_tracing" +MODULE_PREFIX = "unit.test_tracing" @pytest.fixture @@ -128,10 +128,10 @@ def greeting(name, message): # and use service name as a metadata namespace assert in_subsegment_mock.in_subsegment.call_count == 1 assert in_subsegment_mock.in_subsegment.call_args == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_method..greeting" + name=f"## {MODULE_PREFIX}.test_tracer_method..greeting" ) assert in_subsegment_mock.put_metadata.call_args == mocker.call( - key=f"{__MODULE_PREFIX__}.test_tracer_method..greeting response", + key=f"{MODULE_PREFIX}.test_tracer_method..greeting response", value=dummy_response, namespace="booking", ) @@ -261,7 +261,7 @@ def greeting(name, message): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == f"{__MODULE_PREFIX__}.test_tracer_method_exception_metadata..greeting error" + == f"{MODULE_PREFIX}.test_tracer_method_exception_metadata..greeting error" ) assert put_metadata_mock_args["namespace"] == "booking" @@ -315,20 +315,20 @@ async def greeting(name, message): # THEN we should add metadata for each response like we would for a sync decorated method assert in_subsegment_mock.in_subsegment.call_count == 2 assert in_subsegment_greeting_call_args == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting" + name=f"## {MODULE_PREFIX}.test_tracer_method_nested_async..greeting" ) assert in_subsegment_greeting2_call_args == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting_2" + name=f"## {MODULE_PREFIX}.test_tracer_method_nested_async..greeting_2" ) assert in_subsegment_mock.put_metadata.call_count == 2 assert put_metadata_greeting2_call_args == mocker.call( - key=f"{__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting_2 response", + key=f"{MODULE_PREFIX}.test_tracer_method_nested_async..greeting_2 response", value=dummy_response, namespace="booking", ) assert put_metadata_greeting_call_args == mocker.call( - key=f"{__MODULE_PREFIX__}.test_tracer_method_nested_async..greeting response", + key=f"{MODULE_PREFIX}.test_tracer_method_nested_async..greeting response", value=dummy_response, namespace="booking", ) @@ -374,7 +374,7 @@ async def greeting(name, message): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == f"{__MODULE_PREFIX__}.test_tracer_method_exception_metadata_async..greeting error" + == f"{MODULE_PREFIX}.test_tracer_method_exception_metadata_async..greeting error" ) assert put_metadata_mock_args["namespace"] == "booking" @@ -408,7 +408,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert yield_function_trace == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_context_manager..yield_with_capture" + name=f"## {MODULE_PREFIX}.test_tracer_yield_from_context_manager..yield_with_capture" ) assert "test result" in result @@ -435,7 +435,7 @@ def yield_with_capture(): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == f"{__MODULE_PREFIX__}.test_tracer_yield_from_context_manager_exception_metadata..yield_with_capture error" # noqa E501 + == f"{MODULE_PREFIX}.test_tracer_yield_from_context_manager_exception_metadata..yield_with_capture error" # noqa E501 ) assert isinstance(put_metadata_mock_args["value"], ValueError) assert put_metadata_mock_args["namespace"] == "booking" @@ -479,7 +479,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert yield_function_trace == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_nested_context_manager..yield_with_capture" + name=f"## {MODULE_PREFIX}.test_tracer_yield_from_nested_context_manager..yield_with_capture" ) assert "test result" in result @@ -511,7 +511,7 @@ def handler(event, context): assert in_subsegment_mock.in_subsegment.call_count == 2 assert handler_trace == mocker.call(name="## handler") assert generator_fn_trace == mocker.call( - name=f"## {__MODULE_PREFIX__}.test_tracer_yield_from_generator..generator_fn" + name=f"## {MODULE_PREFIX}.test_tracer_yield_from_generator..generator_fn" ) assert "test result" in result @@ -537,7 +537,7 @@ def generator_fn(): put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert ( put_metadata_mock_args["key"] - == f"{__MODULE_PREFIX__}.test_tracer_yield_from_generator_exception_metadata..generator_fn error" + == f"{MODULE_PREFIX}.test_tracer_yield_from_generator_exception_metadata..generator_fn error" ) assert put_metadata_mock_args["namespace"] == "booking" assert isinstance(put_metadata_mock_args["value"], ValueError)