aws-lambda-powertools 3.28.0__tar.gz → 3.29.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/PKG-INFO +2 -2
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/api_gateway.py +206 -10
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/http_resolver.py +5 -69
- aws_lambda_powertools-3.29.0/aws_lambda_powertools/event_handler/middlewares/async_utils.py +224 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py +5 -1
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/params.py +3 -1
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/version.py +1 -1
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/base.py +2 -2
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/redis.py +2 -2
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw_websocket.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/base.py +5 -1
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/bedrock_agent.py +7 -7
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/kafka.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis_firehose.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/sns.py +7 -7
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/sqs.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_lattice.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_latticev2.py +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/functions.py +2 -2
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/parser.py +5 -1
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/pyproject.toml +4 -4
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/setup.py +3 -3
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/LICENSE +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/README.md +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/THIRD-PARTY-LICENSES +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/appsync.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/bedrock_agent_function.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/content_types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/depends.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/appsync_events.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/router.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/events_appsync/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/exception_handling.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/graphql_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/graphql_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/graphql_appsync/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/graphql_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/graphql_appsync/router.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/middlewares/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/middlewares/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/middlewares/schema_validation.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/compat.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/config.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/dependant.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/encoders.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/merge.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/models.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/pydantic_loader.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/schema_generator.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/oauth2.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui-bundle.min.js +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui.min.css +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/openapi/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/request.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/router.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/util.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/event_handler/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/exceptions/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/buffer/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/buffer/cache.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/buffer/config.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/buffer/functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/buffer/handler.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/correlation_paths.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/filters.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/formatter.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/formatters/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/formatters/datadog.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/lambda_context.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/logger.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/logging/utils.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/metric.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/metrics.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/metric_properties.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/cold_start.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/datadog/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/datadog/datadog.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/datadog/metrics.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/provider/datadog/warnings.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/metrics/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/middleware_factory/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/middleware_factory/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/middleware_factory/factory.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/package_logger.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/py.typed +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/cache_dict.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/cookies.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/dynamodb_deserializer.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/headers_serializer.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/json_encoder.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/lazy_import.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/shared/user_agent.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/tracing/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/tracing/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/tracing/extensions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/tracing/tracer.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/decorators.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/batch/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/active_mq_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/alb_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_websocket_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/appsync/scalar_types_utils.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_events_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_function_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_alarm_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_custom_widget_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/cloudformation_custom_resource_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/code_deploy_lifecycle_hook_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/common.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/event_bridge_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/event_source.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/iot_registry_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/kafka_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/lambda_function_url_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/s3_batch_operation_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/s3_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/secrets_manager_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/ses_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/shared_functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/sns_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/sqs_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/provider/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/appconfig.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/comparators.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/feature_flags.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/schema.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/feature_flags/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/config.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/hook.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/idempotency.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/cache.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/datarecord.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/functions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/no_op.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/idempotency/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/jmespath_utils/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/jmespath_utils/envelopes.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/consumer_records.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/avro.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/default.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/deserializer.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/json.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/deserializer/protobuf.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/kafka_consumer.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/schema_config.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/serialization.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/kafka/serialization/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/metadata/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/metadata/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/metadata/lambda_metadata.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/appconfig.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/dynamodb.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/secrets.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/ssm.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parameters/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/envelopes/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/alb.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/apigw.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/apigw_websocket.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/apigwv2.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/appsync.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/appsync_events.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/cognito.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/dynamodb.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/event_bridge.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/iot_registry_events.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/kafka.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/kinesis.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose_sqs.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/s3.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/s3_batch_operation.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/s3_event_notification.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/ses.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/sns.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/sqs.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/transfer_family.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/models/vpc_latticev2.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/parser/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/serialization.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/_s3_seekable_io.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/compat.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/constants.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/s3_object.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/transformations/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/transformations/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/transformations/csv.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/transformations/gzip.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/transformations/zip.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/streaming/types.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/typing/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/typing/lambda_client_context.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/typing/lambda_context.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/validation/__init__.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/validation/base.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/validation/envelopes.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/validation/exceptions.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/utilities/validation/validator.py +0 -0
- {aws_lambda_powertools-3.28.0 → aws_lambda_powertools-3.29.0}/aws_lambda_powertools/warnings/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: aws_lambda_powertools
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.29.0
|
|
4
4
|
Summary: Powertools for AWS Lambda (Python) is a developer toolkit to implement Serverless best practices and increase developer velocity.
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: aws_lambda_powertools,aws,tracing,logging,lambda,powertools,feature_flags,idempotency,middleware
|
|
@@ -29,7 +29,7 @@ Provides-Extra: tracer
|
|
|
29
29
|
Provides-Extra: validation
|
|
30
30
|
Provides-Extra: valkey
|
|
31
31
|
Requires-Dist: avro (>=1.12.0,<2.0.0) ; extra == "kafka-consumer-avro"
|
|
32
|
-
Requires-Dist: aws-encryption-sdk (>=3.1.1,<5.0.0) ; extra == "all" or extra == "datamasking"
|
|
32
|
+
Requires-Dist: aws-encryption-sdk (>=3.3.1,!=4.0.0,!=4.0.1,!=4.0.2,!=4.0.3,!=4.0.4,<5.0.0) ; extra == "all" or extra == "datamasking"
|
|
33
33
|
Requires-Dist: aws-xray-sdk (>=2.8.0,<3.0.0) ; extra == "tracer" or extra == "all"
|
|
34
34
|
Requires-Dist: boto3 (>=1.34.32,<2.0.0) ; extra == "aws-sdk"
|
|
35
35
|
Requires-Dist: datadog-lambda (>=8.114.0,<9.0.0) ; extra == "datadog"
|
|
@@ -613,6 +613,63 @@ class Route:
|
|
|
613
613
|
|
|
614
614
|
self._middleware_stack_built = True
|
|
615
615
|
|
|
616
|
+
async def call_async(
|
|
617
|
+
self,
|
|
618
|
+
router_middlewares: list[Callable],
|
|
619
|
+
app: ApiGatewayResolver,
|
|
620
|
+
route_arguments: dict[str, str],
|
|
621
|
+
) -> dict | tuple | Response:
|
|
622
|
+
from aws_lambda_powertools.event_handler.middlewares.async_utils import (
|
|
623
|
+
AsyncMiddlewareFrame,
|
|
624
|
+
_registered_api_adapter_async,
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
all_middlewares: list[Callable[..., Any]] = []
|
|
628
|
+
|
|
629
|
+
route_validation_enabled = (
|
|
630
|
+
self.enable_validation if self.enable_validation is not None else app._enable_validation
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
if route_validation_enabled and not hasattr(app, "_request_validation_middleware"):
|
|
634
|
+
from aws_lambda_powertools.event_handler.middlewares.openapi_validation import (
|
|
635
|
+
OpenAPIRequestValidationMiddleware,
|
|
636
|
+
OpenAPIResponseValidationMiddleware,
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
app._request_validation_middleware = OpenAPIRequestValidationMiddleware()
|
|
640
|
+
app._response_validation_middleware = OpenAPIResponseValidationMiddleware(
|
|
641
|
+
validation_serializer=app._serializer,
|
|
642
|
+
has_response_validation_error=app._has_response_validation_error,
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
if route_validation_enabled and hasattr(app, "_request_validation_middleware"):
|
|
646
|
+
all_middlewares.append(app._request_validation_middleware)
|
|
647
|
+
|
|
648
|
+
all_middlewares.extend(router_middlewares + self.middlewares)
|
|
649
|
+
|
|
650
|
+
if route_validation_enabled and hasattr(app, "_response_validation_middleware"):
|
|
651
|
+
all_middlewares.append(app._response_validation_middleware)
|
|
652
|
+
|
|
653
|
+
all_middlewares.append(_registered_api_adapter_async)
|
|
654
|
+
|
|
655
|
+
logger.debug(f"Building async middleware stack: {all_middlewares}")
|
|
656
|
+
|
|
657
|
+
if app._debug:
|
|
658
|
+
print(f"\nProcessing Route (async):::{self.func.__name__} ({app.context['_path']})")
|
|
659
|
+
print("\nAsync Middleware Stack:")
|
|
660
|
+
print("=================")
|
|
661
|
+
print("\n".join(getattr(item, "__name__", "Unknown") for item in all_middlewares))
|
|
662
|
+
print("=================")
|
|
663
|
+
|
|
664
|
+
app.append_context(_route_args=route_arguments)
|
|
665
|
+
|
|
666
|
+
# Build async chain from inside-out (not cached, avoids state conflicts with sync cache)
|
|
667
|
+
next_handler: Callable = self.func
|
|
668
|
+
for handler in reversed(all_middlewares):
|
|
669
|
+
next_handler = AsyncMiddlewareFrame(current_middleware=handler, next_middleware=next_handler)
|
|
670
|
+
|
|
671
|
+
return await next_handler(app)
|
|
672
|
+
|
|
616
673
|
@property
|
|
617
674
|
def dependant(self) -> Dependant:
|
|
618
675
|
if self._dependant is None:
|
|
@@ -2509,6 +2566,154 @@ class ApiGatewayResolver(BaseRouter):
|
|
|
2509
2566
|
|
|
2510
2567
|
return response
|
|
2511
2568
|
|
|
2569
|
+
async def resolve_async(self, event: Mapping[str, Any], context: LambdaContext) -> dict[str, Any]:
|
|
2570
|
+
"""Async version of resolve() for native async handler support.
|
|
2571
|
+
|
|
2572
|
+
Use this method when your route handlers use async/await. The resolution
|
|
2573
|
+
pipeline supports both sync and async handlers transparently.
|
|
2574
|
+
|
|
2575
|
+
Parameters
|
|
2576
|
+
----------
|
|
2577
|
+
event: dict[str, Any]
|
|
2578
|
+
Event
|
|
2579
|
+
context: LambdaContext
|
|
2580
|
+
Lambda context
|
|
2581
|
+
Returns
|
|
2582
|
+
-------
|
|
2583
|
+
dict
|
|
2584
|
+
Returns the dict response
|
|
2585
|
+
|
|
2586
|
+
Example
|
|
2587
|
+
-------
|
|
2588
|
+
|
|
2589
|
+
```python
|
|
2590
|
+
import asyncio
|
|
2591
|
+
from aws_lambda_powertools.event_handler import APIGatewayHttpResolver
|
|
2592
|
+
|
|
2593
|
+
app = APIGatewayHttpResolver()
|
|
2594
|
+
|
|
2595
|
+
@app.get("/async")
|
|
2596
|
+
async def async_handler():
|
|
2597
|
+
return {"message": "async works"}
|
|
2598
|
+
|
|
2599
|
+
def lambda_handler(event, context):
|
|
2600
|
+
return asyncio.run(app.resolve_async(event, context))
|
|
2601
|
+
```
|
|
2602
|
+
"""
|
|
2603
|
+
if isinstance(event, BaseProxyEvent):
|
|
2604
|
+
warnings.warn(
|
|
2605
|
+
"You don't need to serialize event to Event Source Data Class when using Event Handler; "
|
|
2606
|
+
"see issue #1152",
|
|
2607
|
+
stacklevel=2,
|
|
2608
|
+
)
|
|
2609
|
+
event = event.raw_event
|
|
2610
|
+
|
|
2611
|
+
if self._debug:
|
|
2612
|
+
print(self._serializer(cast(dict, event)))
|
|
2613
|
+
|
|
2614
|
+
BaseRouter.current_event = self._to_proxy_event(cast(dict, event))
|
|
2615
|
+
BaseRouter.lambda_context = context
|
|
2616
|
+
|
|
2617
|
+
response = (await self._resolve_async()).build(self.current_event, self._cors)
|
|
2618
|
+
|
|
2619
|
+
if self._debug:
|
|
2620
|
+
print("\nProcessed Middlewares:")
|
|
2621
|
+
print("======================")
|
|
2622
|
+
print("\n".join(self.processed_stack_frames))
|
|
2623
|
+
print("======================")
|
|
2624
|
+
|
|
2625
|
+
self.clear_context()
|
|
2626
|
+
|
|
2627
|
+
return response
|
|
2628
|
+
|
|
2629
|
+
async def _resolve_async(self) -> ResponseBuilder:
|
|
2630
|
+
method = self.current_event.http_method.upper()
|
|
2631
|
+
path = self._remove_prefix(self.current_event.path)
|
|
2632
|
+
|
|
2633
|
+
registered_routes = self._static_routes + self._dynamic_routes
|
|
2634
|
+
|
|
2635
|
+
for route in registered_routes:
|
|
2636
|
+
if method != route.method:
|
|
2637
|
+
continue
|
|
2638
|
+
match_results: Match | None = route.rule.match(path)
|
|
2639
|
+
if match_results:
|
|
2640
|
+
logger.debug("Found a registered route. Calling async function")
|
|
2641
|
+
self.append_context(_route=route, _path=path)
|
|
2642
|
+
|
|
2643
|
+
route_keys = self._convert_matches_into_route_keys(match_results)
|
|
2644
|
+
return await self._call_route_async(route, route_keys)
|
|
2645
|
+
|
|
2646
|
+
return await self._handle_not_found_async(method=method, path=path)
|
|
2647
|
+
|
|
2648
|
+
async def _call_route_async(self, route: Route, route_arguments: dict[str, str]) -> ResponseBuilder:
|
|
2649
|
+
try:
|
|
2650
|
+
self._reset_processed_stack()
|
|
2651
|
+
|
|
2652
|
+
response = await route.call_async(
|
|
2653
|
+
router_middlewares=self._router_middlewares,
|
|
2654
|
+
app=self,
|
|
2655
|
+
route_arguments=route_arguments,
|
|
2656
|
+
)
|
|
2657
|
+
|
|
2658
|
+
return self._response_builder_class(
|
|
2659
|
+
response=self._to_response(response), # type: ignore[arg-type]
|
|
2660
|
+
serializer=self._serializer,
|
|
2661
|
+
route=route,
|
|
2662
|
+
)
|
|
2663
|
+
except Exception as exc:
|
|
2664
|
+
response_builder = self._call_exception_handler(exc, route)
|
|
2665
|
+
if response_builder:
|
|
2666
|
+
return response_builder
|
|
2667
|
+
|
|
2668
|
+
logger.exception(exc)
|
|
2669
|
+
if self._debug:
|
|
2670
|
+
return self._response_builder_class(
|
|
2671
|
+
response=Response(
|
|
2672
|
+
status_code=500,
|
|
2673
|
+
content_type=content_types.TEXT_PLAIN,
|
|
2674
|
+
body="".join(traceback.format_exc()),
|
|
2675
|
+
),
|
|
2676
|
+
serializer=self._serializer,
|
|
2677
|
+
route=route,
|
|
2678
|
+
)
|
|
2679
|
+
|
|
2680
|
+
raise
|
|
2681
|
+
|
|
2682
|
+
async def _handle_not_found_async(self, method: str, path: str) -> ResponseBuilder:
|
|
2683
|
+
logger.debug(f"No match found for path {path} and method {method}")
|
|
2684
|
+
|
|
2685
|
+
def not_found_handler():
|
|
2686
|
+
_headers: dict[str, Any] = {}
|
|
2687
|
+
|
|
2688
|
+
if self._cors and method == "OPTIONS":
|
|
2689
|
+
logger.debug("Pre-flight request detected. Returning CORS with empty response")
|
|
2690
|
+
_headers["Access-Control-Allow-Methods"] = CORSConfig.build_allow_methods(self._cors_methods)
|
|
2691
|
+
return Response(status_code=204, content_type=None, headers=_headers, body="")
|
|
2692
|
+
|
|
2693
|
+
custom_not_found_handler = self.exception_handler_manager.lookup_exception_handler(NotFoundError)
|
|
2694
|
+
if custom_not_found_handler:
|
|
2695
|
+
return custom_not_found_handler(NotFoundError())
|
|
2696
|
+
|
|
2697
|
+
return Response(
|
|
2698
|
+
status_code=HTTPStatus.NOT_FOUND.value,
|
|
2699
|
+
content_type=content_types.APPLICATION_JSON,
|
|
2700
|
+
headers=_headers,
|
|
2701
|
+
body={"statusCode": HTTPStatus.NOT_FOUND.value, "message": "Not found"},
|
|
2702
|
+
)
|
|
2703
|
+
|
|
2704
|
+
route = Route(
|
|
2705
|
+
rule=self._compile_regex(r".*"),
|
|
2706
|
+
method=method,
|
|
2707
|
+
path=path,
|
|
2708
|
+
func=not_found_handler,
|
|
2709
|
+
cors=self._cors_enabled,
|
|
2710
|
+
compress=False,
|
|
2711
|
+
)
|
|
2712
|
+
|
|
2713
|
+
self.append_context(_route=route, _path=path)
|
|
2714
|
+
|
|
2715
|
+
return await self._call_route_async(route=route, route_arguments={})
|
|
2716
|
+
|
|
2512
2717
|
def __call__(self, event, context) -> Any:
|
|
2513
2718
|
return self.resolve(event, context)
|
|
2514
2719
|
|
|
@@ -3138,22 +3343,13 @@ class ALBResolver(ApiGatewayResolver):
|
|
|
3138
3343
|
# ALB doesn't have a stage variable, so we just return an empty string
|
|
3139
3344
|
return ""
|
|
3140
3345
|
|
|
3141
|
-
# BedrockResponse is not used here but adding the same signature to keep strong typing
|
|
3142
3346
|
@override
|
|
3143
3347
|
def _to_response(self, result: dict | tuple | Response | BedrockResponse) -> Response | BedrockResponse:
|
|
3144
3348
|
"""Convert the route's result to a Response
|
|
3145
3349
|
|
|
3146
3350
|
ALB requires a non-null body otherwise it converts as HTTP 5xx
|
|
3147
|
-
|
|
3148
|
-
3 main result types are supported:
|
|
3149
|
-
|
|
3150
|
-
- Dict[str, Any]: Rest api response with just the Dict to json stringify and content-type is set to
|
|
3151
|
-
application/json
|
|
3152
|
-
- Tuple[dict, int]: Same dict handling as above but with the option of including a status code
|
|
3153
|
-
- Response: returned as is, and allows for more flexibility
|
|
3154
3351
|
"""
|
|
3155
|
-
|
|
3156
|
-
# NOTE: Minor override for early return on Response with null body for ALB
|
|
3352
|
+
# ALB doesn't support null body - convert before building the final response
|
|
3157
3353
|
if isinstance(result, Response) and result.body is None:
|
|
3158
3354
|
logger.debug("ALB doesn't allow None responses; converting to empty string")
|
|
3159
3355
|
result.body = ""
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
import base64
|
|
5
4
|
import inspect
|
|
6
|
-
import threading
|
|
7
5
|
import warnings
|
|
8
6
|
from typing import TYPE_CHECKING, Any, Callable
|
|
9
7
|
from urllib.parse import parse_qs
|
|
@@ -15,6 +13,7 @@ from aws_lambda_powertools.event_handler.api_gateway import (
|
|
|
15
13
|
Response,
|
|
16
14
|
Route,
|
|
17
15
|
)
|
|
16
|
+
from aws_lambda_powertools.event_handler.middlewares.async_utils import wrap_middleware_async
|
|
18
17
|
from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer
|
|
19
18
|
from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent
|
|
20
19
|
|
|
@@ -240,7 +239,7 @@ class HttpResolverLocal(ApiGatewayResolver):
|
|
|
240
239
|
"""Return the base path for HTTP resolver (no stage prefix)."""
|
|
241
240
|
return ""
|
|
242
241
|
|
|
243
|
-
async def _resolve_async(self) -> dict:
|
|
242
|
+
async def _resolve_async(self) -> dict: # type: ignore[override]
|
|
244
243
|
"""Async version of resolve that supports async handlers."""
|
|
245
244
|
method = self.current_event.http_method.upper()
|
|
246
245
|
path = self._remove_prefix(self.current_event.path)
|
|
@@ -259,7 +258,7 @@ class HttpResolverLocal(ApiGatewayResolver):
|
|
|
259
258
|
# Handle not found
|
|
260
259
|
return await self._handle_not_found_async()
|
|
261
260
|
|
|
262
|
-
async def _call_route_async(self, route: Route, route_arguments: dict[str, str]) -> dict:
|
|
261
|
+
async def _call_route_async(self, route: Route, route_arguments: dict[str, str]) -> dict: # type: ignore[override]
|
|
263
262
|
"""Call route handler, supporting both sync and async handlers."""
|
|
264
263
|
from aws_lambda_powertools.event_handler.api_gateway import ResponseBuilder
|
|
265
264
|
|
|
@@ -320,74 +319,11 @@ class HttpResolverLocal(ApiGatewayResolver):
|
|
|
320
319
|
next_handler = final_handler
|
|
321
320
|
|
|
322
321
|
for middleware in reversed(all_middlewares):
|
|
323
|
-
next_handler =
|
|
322
|
+
next_handler = wrap_middleware_async(middleware, next_handler)
|
|
324
323
|
|
|
325
324
|
return await next_handler(self)
|
|
326
325
|
|
|
327
|
-
def
|
|
328
|
-
"""Wrap a middleware to work in async context.
|
|
329
|
-
|
|
330
|
-
For sync middlewares, we split execution into pre/post phases around the
|
|
331
|
-
call to next(). The sync middleware runs its pre-processing (e.g. request
|
|
332
|
-
validation), then we intercept the next() call, await the async handler,
|
|
333
|
-
and resume the middleware with the real response so post-processing
|
|
334
|
-
(e.g. response validation) sees the actual data.
|
|
335
|
-
"""
|
|
336
|
-
|
|
337
|
-
async def wrapped(app):
|
|
338
|
-
if inspect.iscoroutinefunction(middleware):
|
|
339
|
-
return await middleware(app, next_handler)
|
|
340
|
-
|
|
341
|
-
# We use an Event to coordinate: the sync middleware runs in a thread,
|
|
342
|
-
# calls sync_next which signals us to resolve the async handler,
|
|
343
|
-
# then waits for the real response.
|
|
344
|
-
middleware_called_next = asyncio.Event()
|
|
345
|
-
next_app_holder: list = []
|
|
346
|
-
real_response_holder: list = []
|
|
347
|
-
middleware_result_holder: list = []
|
|
348
|
-
middleware_error_holder: list = []
|
|
349
|
-
|
|
350
|
-
def sync_next(app):
|
|
351
|
-
next_app_holder.append(app)
|
|
352
|
-
middleware_called_next.set()
|
|
353
|
-
# Block this thread until the real response is available
|
|
354
|
-
event = threading.Event()
|
|
355
|
-
next_app_holder.append(event)
|
|
356
|
-
event.wait()
|
|
357
|
-
return real_response_holder[0]
|
|
358
|
-
|
|
359
|
-
def run_middleware():
|
|
360
|
-
try:
|
|
361
|
-
result = middleware(app, sync_next)
|
|
362
|
-
middleware_result_holder.append(result)
|
|
363
|
-
except Exception as e:
|
|
364
|
-
middleware_error_holder.append(e)
|
|
365
|
-
|
|
366
|
-
thread = threading.Thread(target=run_middleware, daemon=True)
|
|
367
|
-
thread.start()
|
|
368
|
-
|
|
369
|
-
# Wait for the middleware to call next()
|
|
370
|
-
await middleware_called_next.wait()
|
|
371
|
-
|
|
372
|
-
# Now resolve the async next_handler
|
|
373
|
-
real_response = await next_handler(next_app_holder[0])
|
|
374
|
-
real_response_holder.append(real_response)
|
|
375
|
-
|
|
376
|
-
# Signal the thread that the response is ready
|
|
377
|
-
threading_event = next_app_holder[1]
|
|
378
|
-
threading_event.set()
|
|
379
|
-
|
|
380
|
-
# Wait for the middleware thread to finish
|
|
381
|
-
thread.join()
|
|
382
|
-
|
|
383
|
-
if middleware_error_holder:
|
|
384
|
-
raise middleware_error_holder[0]
|
|
385
|
-
|
|
386
|
-
return middleware_result_holder[0]
|
|
387
|
-
|
|
388
|
-
return wrapped
|
|
389
|
-
|
|
390
|
-
async def _handle_not_found_async(self) -> dict:
|
|
326
|
+
async def _handle_not_found_async(self, method: str = "", path: str = "") -> dict: # type: ignore[override]
|
|
391
327
|
"""Handle 404 responses, using custom not_found handler if registered."""
|
|
392
328
|
from http import HTTPStatus
|
|
393
329
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""Async middleware utilities for bridging sync and async middleware execution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import inspect
|
|
7
|
+
import logging
|
|
8
|
+
import threading
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Callable
|
|
15
|
+
|
|
16
|
+
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver, BedrockResponse, Response
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def wrap_middleware_async(middleware: Callable, next_handler: Callable) -> Callable:
|
|
20
|
+
"""Wrap a middleware to work in an async context.
|
|
21
|
+
|
|
22
|
+
For async middlewares, delegates directly with ``await``.
|
|
23
|
+
|
|
24
|
+
For sync middlewares, runs the middleware in a background thread and uses
|
|
25
|
+
``asyncio.Event`` / ``threading.Event`` to coordinate the ``next()`` call
|
|
26
|
+
so the async handler can be awaited on the main event-loop while the sync
|
|
27
|
+
middleware blocks its own thread waiting for the result.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
middleware : Callable
|
|
32
|
+
A sync or async middleware ``(app, next_middleware) -> Response``.
|
|
33
|
+
next_handler : Callable
|
|
34
|
+
The next (async) handler in the chain.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
Callable
|
|
39
|
+
An async callable ``(app) -> Response`` that executes *middleware*
|
|
40
|
+
followed by *next_handler*.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
async def wrapped(app: ApiGatewayResolver) -> Response:
|
|
44
|
+
if inspect.iscoroutinefunction(middleware):
|
|
45
|
+
return await middleware(app, next_handler)
|
|
46
|
+
|
|
47
|
+
return await _run_sync_middleware_in_thread(middleware, next_handler, app)
|
|
48
|
+
|
|
49
|
+
return wrapped
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def _run_sync_middleware_in_thread(
|
|
53
|
+
middleware: Callable,
|
|
54
|
+
next_handler: Callable,
|
|
55
|
+
app: Any,
|
|
56
|
+
) -> Any:
|
|
57
|
+
"""Execute a **sync** middleware inside a daemon thread.
|
|
58
|
+
|
|
59
|
+
The sync middleware calls ``sync_next(app)`` which:
|
|
60
|
+
|
|
61
|
+
1. Signals the async side that the middleware is ready for the next handler.
|
|
62
|
+
2. Blocks the thread until the async handler has produced a response.
|
|
63
|
+
3. Returns the response so the middleware can do post-processing.
|
|
64
|
+
|
|
65
|
+
Meanwhile the async side awaits *next_handler*, feeds the response back,
|
|
66
|
+
and waits for the thread to finish.
|
|
67
|
+
"""
|
|
68
|
+
middleware_called_next = asyncio.Event()
|
|
69
|
+
next_app_holder: list = []
|
|
70
|
+
real_response_holder: list = []
|
|
71
|
+
middleware_result_holder: list = []
|
|
72
|
+
middleware_error_holder: list = []
|
|
73
|
+
|
|
74
|
+
def sync_next(app: Any) -> Any:
|
|
75
|
+
next_app_holder.append(app)
|
|
76
|
+
middleware_called_next.set()
|
|
77
|
+
# Block this thread until the async handler resolves
|
|
78
|
+
event = threading.Event()
|
|
79
|
+
next_app_holder.append(event)
|
|
80
|
+
event.wait()
|
|
81
|
+
return real_response_holder[0]
|
|
82
|
+
|
|
83
|
+
def run_middleware() -> None:
|
|
84
|
+
try:
|
|
85
|
+
result = middleware(app, sync_next)
|
|
86
|
+
middleware_result_holder.append(result)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
middleware_error_holder.append(e)
|
|
89
|
+
finally:
|
|
90
|
+
middleware_called_next.set()
|
|
91
|
+
|
|
92
|
+
thread = threading.Thread(target=run_middleware, daemon=True)
|
|
93
|
+
thread.start()
|
|
94
|
+
|
|
95
|
+
# Wait for the middleware to call next() or raise
|
|
96
|
+
await middleware_called_next.wait()
|
|
97
|
+
|
|
98
|
+
# If middleware raised before calling next, propagate immediately
|
|
99
|
+
if not next_app_holder:
|
|
100
|
+
thread.join()
|
|
101
|
+
raise middleware_error_holder[0]
|
|
102
|
+
|
|
103
|
+
# Resolve the async next_handler on the event-loop
|
|
104
|
+
real_response = await next_handler(next_app_holder[0])
|
|
105
|
+
real_response_holder.append(real_response)
|
|
106
|
+
|
|
107
|
+
# Unblock the middleware thread
|
|
108
|
+
threading_event = next_app_holder[1]
|
|
109
|
+
threading_event.set()
|
|
110
|
+
|
|
111
|
+
# Wait for the middleware thread to complete post-processing
|
|
112
|
+
thread.join()
|
|
113
|
+
|
|
114
|
+
if middleware_error_holder:
|
|
115
|
+
raise middleware_error_holder[0]
|
|
116
|
+
|
|
117
|
+
return middleware_result_holder[0]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class AsyncMiddlewareFrame:
|
|
121
|
+
"""Async version of MiddlewareFrame for the async middleware chain.
|
|
122
|
+
|
|
123
|
+
Each instance wraps a middleware (sync or async) and the next handler in the stack.
|
|
124
|
+
When called, it auto-detects whether the current middleware is sync or async:
|
|
125
|
+
|
|
126
|
+
- **Async middleware**: awaited directly with ``(app, next_middleware)``
|
|
127
|
+
- **Sync middleware**: executed in a background thread so the event loop is never blocked
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
current_middleware : Callable
|
|
132
|
+
The current middleware function to be called as a request is processed.
|
|
133
|
+
next_middleware : Callable
|
|
134
|
+
The next middleware in the middleware stack.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def __init__(
|
|
138
|
+
self,
|
|
139
|
+
current_middleware: Callable[..., Any],
|
|
140
|
+
next_middleware: Callable[..., Any],
|
|
141
|
+
) -> None:
|
|
142
|
+
self.current_middleware: Callable[..., Any] = current_middleware
|
|
143
|
+
self.next_middleware: Callable[..., Any] = next_middleware
|
|
144
|
+
self._next_middleware_name = next_middleware.__name__
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def __name__(self) -> str: # noqa: A003
|
|
148
|
+
return self.current_middleware.__name__
|
|
149
|
+
|
|
150
|
+
def __str__(self) -> str:
|
|
151
|
+
middleware_name = self.__name__
|
|
152
|
+
return f"[{middleware_name}] next call chain is {middleware_name} -> {self._next_middleware_name}"
|
|
153
|
+
|
|
154
|
+
async def __call__(self, app: ApiGatewayResolver) -> dict | tuple | Response:
|
|
155
|
+
logger.debug("AsyncMiddlewareFrame: %s", self)
|
|
156
|
+
app._push_processed_stack_frame(str(self))
|
|
157
|
+
|
|
158
|
+
if inspect.iscoroutinefunction(self.current_middleware):
|
|
159
|
+
return await self.current_middleware(app, self.next_middleware)
|
|
160
|
+
|
|
161
|
+
loop = asyncio.get_running_loop()
|
|
162
|
+
|
|
163
|
+
def sync_next(app: ApiGatewayResolver) -> Any:
|
|
164
|
+
future = asyncio.run_coroutine_threadsafe(self.next_middleware(app), loop)
|
|
165
|
+
return future.result()
|
|
166
|
+
|
|
167
|
+
return await asyncio.to_thread(self.current_middleware, app, sync_next)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
async def _registered_api_adapter_async(
|
|
171
|
+
app: ApiGatewayResolver,
|
|
172
|
+
next_middleware: Callable[..., Any],
|
|
173
|
+
) -> dict | tuple | Response | BedrockResponse:
|
|
174
|
+
"""
|
|
175
|
+
Async version of _registered_api_adapter.
|
|
176
|
+
|
|
177
|
+
Detects if the route handler is a coroutine and awaits it.
|
|
178
|
+
_to_response() stays sync (CPU-bound — no async benefit).
|
|
179
|
+
|
|
180
|
+
IMPORTANT: This is an internal building block only.
|
|
181
|
+
Nothing calls it in the resolve chain yet. It will be used
|
|
182
|
+
by resolve_async() (see issue #8137).
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
app: ApiGatewayResolver
|
|
187
|
+
The API Gateway resolver
|
|
188
|
+
next_middleware: Callable[..., Any]
|
|
189
|
+
The function to handle the API
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
Response
|
|
194
|
+
The API Response Object
|
|
195
|
+
"""
|
|
196
|
+
route_args: dict = app.context.get("_route_args", {})
|
|
197
|
+
logger.debug(f"Calling API Route Handler: {route_args}")
|
|
198
|
+
|
|
199
|
+
route = app.context.get("_route")
|
|
200
|
+
if route is not None:
|
|
201
|
+
if not route.request_param_name_checked:
|
|
202
|
+
from aws_lambda_powertools.event_handler.api_gateway import _find_request_param_name
|
|
203
|
+
|
|
204
|
+
route.request_param_name = _find_request_param_name(next_middleware)
|
|
205
|
+
route.request_param_name_checked = True
|
|
206
|
+
if route.request_param_name:
|
|
207
|
+
route_args = {**route_args, route.request_param_name: app.request}
|
|
208
|
+
|
|
209
|
+
if route.has_dependencies:
|
|
210
|
+
from aws_lambda_powertools.event_handler.depends import build_dependency_tree, solve_dependencies
|
|
211
|
+
|
|
212
|
+
dep_values = solve_dependencies(
|
|
213
|
+
dependant=build_dependency_tree(route.func),
|
|
214
|
+
request=app.request,
|
|
215
|
+
dependency_overrides=app.dependency_overrides or None,
|
|
216
|
+
)
|
|
217
|
+
route_args.update(dep_values)
|
|
218
|
+
|
|
219
|
+
# Call handler — detect if result is a coroutine and await it
|
|
220
|
+
result = next_middleware(**route_args)
|
|
221
|
+
if inspect.iscoroutine(result):
|
|
222
|
+
result = await result
|
|
223
|
+
|
|
224
|
+
return app._to_response(result)
|
|
@@ -296,9 +296,13 @@ class OpenAPIResponseValidationMiddleware(BaseMiddlewareHandler):
|
|
|
296
296
|
# JSON serialize the body without validation
|
|
297
297
|
response.body = jsonable_encoder(response.body, custom_serializer=self._validation_serializer)
|
|
298
298
|
else:
|
|
299
|
+
# ALB resolver converts None body to "" to prevent ALB 5xx errors,
|
|
300
|
+
# but the validation should still see it as None.
|
|
301
|
+
response_content = None if response.body == "" and field.type_ in (None, type(None)) else response.body
|
|
302
|
+
|
|
299
303
|
response.body = self._serialize_response_with_validation(
|
|
300
304
|
field=field,
|
|
301
|
-
response_content=
|
|
305
|
+
response_content=response_content,
|
|
302
306
|
has_route_custom_response_validation=route.custom_response_validation_http_code is not None,
|
|
303
307
|
)
|
|
304
308
|
|
|
@@ -901,7 +901,7 @@ def analyze_param(
|
|
|
901
901
|
if is_response_param:
|
|
902
902
|
field_info.default = Required
|
|
903
903
|
|
|
904
|
-
field = _create_model_field(field_info, type_annotation, param_name, is_path_param)
|
|
904
|
+
field = _create_model_field(field_info, type_annotation, param_name, is_path_param, is_response_param)
|
|
905
905
|
return field
|
|
906
906
|
|
|
907
907
|
|
|
@@ -1138,6 +1138,7 @@ def _create_model_field(
|
|
|
1138
1138
|
type_annotation: Any,
|
|
1139
1139
|
param_name: str,
|
|
1140
1140
|
is_path_param: bool,
|
|
1141
|
+
is_response_param: bool = False,
|
|
1141
1142
|
) -> ModelField | None:
|
|
1142
1143
|
"""
|
|
1143
1144
|
Create a new ModelField from a FieldInfo and type annotation.
|
|
@@ -1164,4 +1165,5 @@ def _create_model_field(
|
|
|
1164
1165
|
alias=field_info.alias,
|
|
1165
1166
|
required=field_info.default in (Required, Undefined),
|
|
1166
1167
|
field_info=field_info,
|
|
1168
|
+
mode="serialization" if is_response_param else "validation",
|
|
1167
1169
|
)
|
|
@@ -167,7 +167,7 @@ class IdempotencyHandler:
|
|
|
167
167
|
# We give preference to ReturnValuesOnConditionCheckFailure because it is a faster and more cost-effective
|
|
168
168
|
# way of retrieving the existing record after a failed conditional write operation.
|
|
169
169
|
record = exc.old_data_record or self._get_idempotency_record()
|
|
170
|
-
if is_replay and record is not None and record.status == "INPROGRESS":
|
|
170
|
+
if is_replay and record is not None and record.status == STATUS_CONSTANTS["INPROGRESS"]:
|
|
171
171
|
return self._get_function_response()
|
|
172
172
|
# If a record is found, handle it for status
|
|
173
173
|
if record:
|
|
@@ -296,7 +296,7 @@ class IdempotencyHandler:
|
|
|
296
296
|
|
|
297
297
|
else:
|
|
298
298
|
try:
|
|
299
|
-
serialized_response: dict = self.output_serializer.to_dict(response) if response else None
|
|
299
|
+
serialized_response: dict = self.output_serializer.to_dict(response) if response is not None else None
|
|
300
300
|
self.persistence_store.save_success(data=self.data, result=serialized_response)
|
|
301
301
|
except Exception as save_exception:
|
|
302
302
|
raise IdempotencyPersistenceLayerError(
|
|
@@ -332,8 +332,8 @@ class RedisCachePersistenceLayer(BasePersistenceLayer):
|
|
|
332
332
|
idempotency_key=idempotency_key,
|
|
333
333
|
status=item[self.status_attr],
|
|
334
334
|
in_progress_expiry_timestamp=in_progress_expiry_timestamp,
|
|
335
|
-
response_data=
|
|
336
|
-
payload_hash=
|
|
335
|
+
response_data=item.get(self.data_attr, ""),
|
|
336
|
+
payload_hash=item.get(self.validation_key_attr, ""),
|
|
337
337
|
expiry_timestamp=item.get("expiration"),
|
|
338
338
|
)
|
|
339
339
|
|