aws-lambda-powertools 3.26.0__tar.gz → 3.27.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.26.0 → aws_lambda_powertools-3.27.0}/PKG-INFO +2 -2
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/__init__.py +2 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/api_gateway.py +76 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/http_resolver.py +55 -25
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py +210 -7
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/dependant.py +10 -4
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/merge.py +11 -4
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/params.py +124 -1
- aws_lambda_powertools-3.27.0/aws_lambda_powertools/event_handler/request.py +115 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/version.py +1 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +4 -4
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +11 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/common.py +42 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/base.py +1 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/feature_flags.py +9 -9
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/base.py +1 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/base.py +4 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/protobuf.py +3 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/metadata/lambda_metadata.py +1 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/base.py +1 -1
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/dynamodb.py +2 -2
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/secrets.py +2 -2
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/ssm.py +2 -2
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/pyproject.toml +7 -7
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/setup.py +2 -2
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/LICENSE +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/README.md +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/THIRD-PARTY-LICENSES +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/appsync.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/bedrock_agent_function.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/content_types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/appsync_events.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/router.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/events_appsync/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/exception_handling.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/graphql_appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/graphql_appsync/_registry.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/graphql_appsync/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/graphql_appsync/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/graphql_appsync/router.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/middlewares/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/middlewares/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/middlewares/schema_validation.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/compat.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/config.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/encoders.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/models.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/pydantic_loader.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/oauth2.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui-bundle.min.js +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui.min.css +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/openapi/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/router.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/util.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/event_handler/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/exceptions/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/buffer/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/buffer/cache.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/buffer/config.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/buffer/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/buffer/handler.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/correlation_paths.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/filters.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/formatter.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/formatters/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/formatters/datadog.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/lambda_context.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/logger.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/logging/utils.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/metric.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/metrics.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/metric_properties.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/cold_start.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/datadog/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/datadog/datadog.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/datadog/metrics.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/provider/datadog/warnings.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/metrics/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/middleware_factory/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/middleware_factory/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/middleware_factory/factory.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/package_logger.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/py.typed +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/cache_dict.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/cookies.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/dynamodb_deserializer.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/headers_serializer.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/json_encoder.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/lazy_import.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/shared/user_agent.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/tracing/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/tracing/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/tracing/extensions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/tracing/tracer.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/decorators.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/batch/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/active_mq_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/alb_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_websocket_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/appsync/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/appsync/scalar_types_utils.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_events_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_function_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_alarm_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_custom_widget_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/cloudformation_custom_resource_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/code_deploy_lifecycle_hook_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/event_bridge_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/event_source.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/iot_registry_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/kafka_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/lambda_function_url_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/s3_batch_operation_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/s3_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/secrets_manager_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/ses_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/shared_functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/sns_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/sqs_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/provider/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/provider/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/appconfig.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/comparators.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/schema.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/feature_flags/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/config.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/hook.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/idempotency.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/cache.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/datarecord.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/persistence/redis.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/no_op.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/idempotency/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/jmespath_utils/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/jmespath_utils/envelopes.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/consumer_records.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/avro.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/default.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/deserializer.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/deserializer/json.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/kafka_consumer.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/schema_config.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/custom_dict.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/dataclass.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/pydantic.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/serialization.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/kafka/serialization/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/metadata/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/metadata/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/appconfig.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parameters/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw_websocket.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/kafka.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis_firehose.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/sns.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/sqs.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_latticev2.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/functions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/alb.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/apigw.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/apigw_websocket.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/apigwv2.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/appsync.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/appsync_events.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/bedrock_agent.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/cloudwatch.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/cognito.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/dynamodb.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/event_bridge.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/iot_registry_events.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/kafka.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/kinesis.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose_sqs.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/lambda_function_url.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/s3.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/s3_batch_operation.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/s3_event_notification.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/s3_object_event.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/ses.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/sns.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/sqs.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/transfer_family.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/vpc_lattice.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/models/vpc_latticev2.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/parser.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/parser/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/serialization.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/_s3_seekable_io.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/compat.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/constants.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/s3_object.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/transformations/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/transformations/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/transformations/csv.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/transformations/gzip.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/transformations/zip.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/streaming/types.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/typing/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/typing/lambda_client_context.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/typing/lambda_context.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/validation/__init__.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/validation/base.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/validation/envelopes.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/validation/exceptions.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.0}/aws_lambda_powertools/utilities/validation/validator.py +0 -0
- {aws_lambda_powertools-3.26.0 → aws_lambda_powertools-3.27.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.27.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
|
|
@@ -36,7 +36,7 @@ Requires-Dist: datadog-lambda (>=8.114.0,<9.0.0) ; extra == "datadog"
|
|
|
36
36
|
Requires-Dist: fastjsonschema (>=2.14.5,<3.0.0) ; extra == "validation" or extra == "all"
|
|
37
37
|
Requires-Dist: jmespath (>=1.0.1,<2.0.0)
|
|
38
38
|
Requires-Dist: jsonpath-ng (>=1.6.0,<2.0.0) ; extra == "all" or extra == "datamasking"
|
|
39
|
-
Requires-Dist: protobuf (>=6.30.2,<
|
|
39
|
+
Requires-Dist: protobuf (>=6.30.2,<8.0.0) ; extra == "kafka-consumer-protobuf"
|
|
40
40
|
Requires-Dist: pydantic (>=2.4.0,<3.0.0) ; extra == "parser" or extra == "all"
|
|
41
41
|
Requires-Dist: pydantic-settings (>=2.6.1,<3.0.0) ; extra == "all"
|
|
42
42
|
Requires-Dist: redis (>=4.4,<8.0) ; extra == "redis"
|
|
@@ -21,6 +21,7 @@ from aws_lambda_powertools.event_handler.http_resolver import HttpResolverLocal
|
|
|
21
21
|
from aws_lambda_powertools.event_handler.lambda_function_url import (
|
|
22
22
|
LambdaFunctionUrlResolver,
|
|
23
23
|
)
|
|
24
|
+
from aws_lambda_powertools.event_handler.request import Request
|
|
24
25
|
from aws_lambda_powertools.event_handler.vpc_lattice import VPCLatticeResolver, VPCLatticeV2Resolver
|
|
25
26
|
|
|
26
27
|
__all__ = [
|
|
@@ -37,6 +38,7 @@ __all__ = [
|
|
|
37
38
|
"CORSConfig",
|
|
38
39
|
"HttpResolverLocal",
|
|
39
40
|
"LambdaFunctionUrlResolver",
|
|
41
|
+
"Request",
|
|
40
42
|
"Response",
|
|
41
43
|
"VPCLatticeResolver",
|
|
42
44
|
"VPCLatticeV2Resolver",
|
|
@@ -42,6 +42,7 @@ from aws_lambda_powertools.event_handler.openapi.types import (
|
|
|
42
42
|
validation_error_definition,
|
|
43
43
|
validation_error_response_definition,
|
|
44
44
|
)
|
|
45
|
+
from aws_lambda_powertools.event_handler.request import Request
|
|
45
46
|
from aws_lambda_powertools.event_handler.util import (
|
|
46
47
|
_FrozenDict,
|
|
47
48
|
_FrozenListDict,
|
|
@@ -466,6 +467,11 @@ class Route:
|
|
|
466
467
|
|
|
467
468
|
self.custom_response_validation_http_code = custom_response_validation_http_code
|
|
468
469
|
|
|
470
|
+
# Caches the name of any Request-typed parameter in the handler.
|
|
471
|
+
# Avoids re-scanning the signature on every invocation.
|
|
472
|
+
self.request_param_name: str | None = None
|
|
473
|
+
self.request_param_name_checked: bool = False
|
|
474
|
+
|
|
469
475
|
def __call__(
|
|
470
476
|
self,
|
|
471
477
|
router_middlewares: list[Callable],
|
|
@@ -1608,6 +1614,47 @@ class BaseRouter(ABC):
|
|
|
1608
1614
|
"""Resets routing context"""
|
|
1609
1615
|
self.context.clear()
|
|
1610
1616
|
|
|
1617
|
+
@property
|
|
1618
|
+
def request(self) -> Request:
|
|
1619
|
+
"""Current resolved :class:`Request` object.
|
|
1620
|
+
|
|
1621
|
+
Available inside middleware and in route handlers that declare a parameter
|
|
1622
|
+
typed as :class:`Request <aws_lambda_powertools.event_handler.request.Request>`.
|
|
1623
|
+
|
|
1624
|
+
Raises
|
|
1625
|
+
------
|
|
1626
|
+
RuntimeError
|
|
1627
|
+
When accessed before route resolution (i.e. outside of middleware / handler scope).
|
|
1628
|
+
|
|
1629
|
+
Examples
|
|
1630
|
+
--------
|
|
1631
|
+
**Middleware**
|
|
1632
|
+
|
|
1633
|
+
```python
|
|
1634
|
+
def my_middleware(app, next_middleware):
|
|
1635
|
+
req = app.request
|
|
1636
|
+
print(req.route, req.method, req.path_parameters)
|
|
1637
|
+
return next_middleware(app)
|
|
1638
|
+
```
|
|
1639
|
+
"""
|
|
1640
|
+
cached: Request | None = self.context.get("_request")
|
|
1641
|
+
if cached is not None:
|
|
1642
|
+
return cached
|
|
1643
|
+
|
|
1644
|
+
route: Route | None = self.context.get("_route")
|
|
1645
|
+
if route is None:
|
|
1646
|
+
raise RuntimeError(
|
|
1647
|
+
"app.request is only available after route resolution. Use it inside middleware or a route handler.",
|
|
1648
|
+
)
|
|
1649
|
+
|
|
1650
|
+
request = Request(
|
|
1651
|
+
route_path=route.openapi_path,
|
|
1652
|
+
path_parameters=self.context.get("_route_args", {}),
|
|
1653
|
+
current_event=self.current_event,
|
|
1654
|
+
)
|
|
1655
|
+
self.context["_request"] = request
|
|
1656
|
+
return request
|
|
1657
|
+
|
|
1611
1658
|
|
|
1612
1659
|
class MiddlewareFrame:
|
|
1613
1660
|
"""
|
|
@@ -1680,6 +1727,24 @@ class MiddlewareFrame:
|
|
|
1680
1727
|
return self.current_middleware(app, self.next_middleware)
|
|
1681
1728
|
|
|
1682
1729
|
|
|
1730
|
+
def _find_request_param_name(func: Callable) -> str | None:
|
|
1731
|
+
"""Return the name of the first parameter annotated as ``Request``, or ``None``."""
|
|
1732
|
+
from typing import get_type_hints
|
|
1733
|
+
|
|
1734
|
+
try:
|
|
1735
|
+
# get_type_hints resolves string annotations from ``from __future__ import annotations``
|
|
1736
|
+
# using the function's own module globals.
|
|
1737
|
+
hints = get_type_hints(func)
|
|
1738
|
+
except Exception:
|
|
1739
|
+
hints = {}
|
|
1740
|
+
|
|
1741
|
+
for param_name, annotation in hints.items():
|
|
1742
|
+
if annotation is Request:
|
|
1743
|
+
return param_name
|
|
1744
|
+
|
|
1745
|
+
return None
|
|
1746
|
+
|
|
1747
|
+
|
|
1683
1748
|
def _registered_api_adapter(
|
|
1684
1749
|
app: ApiGatewayResolver,
|
|
1685
1750
|
next_middleware: Callable[..., Any],
|
|
@@ -1708,6 +1773,17 @@ def _registered_api_adapter(
|
|
|
1708
1773
|
"""
|
|
1709
1774
|
route_args: dict = app.context.get("_route_args", {})
|
|
1710
1775
|
logger.debug(f"Calling API Route Handler: {route_args}")
|
|
1776
|
+
|
|
1777
|
+
# Inject a Request object when the handler declares a parameter typed as Request.
|
|
1778
|
+
# Lookup is cached on the Route object to avoid repeated signature inspection.
|
|
1779
|
+
route: Route | None = app.context.get("_route")
|
|
1780
|
+
if route is not None:
|
|
1781
|
+
if not route.request_param_name_checked:
|
|
1782
|
+
route.request_param_name = _find_request_param_name(next_middleware)
|
|
1783
|
+
route.request_param_name_checked = True
|
|
1784
|
+
if route.request_param_name:
|
|
1785
|
+
route_args = {**route_args, route.request_param_name: app.request}
|
|
1786
|
+
|
|
1711
1787
|
return app._to_response(next_middleware(**route_args))
|
|
1712
1788
|
|
|
1713
1789
|
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import base64
|
|
5
5
|
import inspect
|
|
6
|
+
import threading
|
|
6
7
|
import warnings
|
|
7
8
|
from typing import TYPE_CHECKING, Any, Callable
|
|
8
9
|
from urllib.parse import parse_qs
|
|
@@ -324,36 +325,65 @@ class HttpResolverLocal(ApiGatewayResolver):
|
|
|
324
325
|
return await next_handler(self)
|
|
325
326
|
|
|
326
327
|
def _wrap_middleware_async(self, middleware: Callable, next_handler: Callable) -> Callable:
|
|
327
|
-
"""Wrap a middleware to work in async context.
|
|
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
|
+
"""
|
|
328
336
|
|
|
329
337
|
async def wrapped(app):
|
|
330
|
-
# Create a next_middleware that the sync middleware can call
|
|
331
|
-
def sync_next(app):
|
|
332
|
-
# This will be called by sync middleware
|
|
333
|
-
# We need to run the async next_handler
|
|
334
|
-
loop = asyncio.get_event_loop()
|
|
335
|
-
if loop.is_running():
|
|
336
|
-
# We're in an async context, create a task
|
|
337
|
-
future = asyncio.ensure_future(next_handler(app))
|
|
338
|
-
# Store for later await
|
|
339
|
-
app.context["_async_next_result"] = future
|
|
340
|
-
return Response(status_code=200, body="") # Placeholder
|
|
341
|
-
else: # pragma: no cover
|
|
342
|
-
return loop.run_until_complete(next_handler(app))
|
|
343
|
-
|
|
344
|
-
# Check if middleware is async
|
|
345
338
|
if inspect.iscoroutinefunction(middleware):
|
|
346
|
-
|
|
347
|
-
else:
|
|
348
|
-
# Sync middleware - need special handling
|
|
349
|
-
result = middleware(app, sync_next)
|
|
339
|
+
return await middleware(app, next_handler)
|
|
350
340
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
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 = []
|
|
355
349
|
|
|
356
|
-
|
|
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]
|
|
357
387
|
|
|
358
388
|
return wrapped
|
|
359
389
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import base64
|
|
3
4
|
import dataclasses
|
|
4
5
|
import json
|
|
5
6
|
import logging
|
|
6
|
-
|
|
7
|
+
import warnings
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, Mapping, MutableMapping, Sequence, Union, cast
|
|
7
9
|
from urllib.parse import parse_qs
|
|
8
10
|
|
|
9
11
|
from pydantic import BaseModel
|
|
12
|
+
from typing_extensions import get_args, get_origin
|
|
10
13
|
|
|
11
14
|
from aws_lambda_powertools.event_handler.middlewares import BaseMiddlewareHandler
|
|
12
15
|
from aws_lambda_powertools.event_handler.openapi.compat import (
|
|
@@ -24,7 +27,8 @@ from aws_lambda_powertools.event_handler.openapi.exceptions import (
|
|
|
24
27
|
RequestValidationError,
|
|
25
28
|
ResponseValidationError,
|
|
26
29
|
)
|
|
27
|
-
from aws_lambda_powertools.event_handler.openapi.params import Param
|
|
30
|
+
from aws_lambda_powertools.event_handler.openapi.params import Param, UploadFile
|
|
31
|
+
from aws_lambda_powertools.event_handler.openapi.types import UnionType
|
|
28
32
|
|
|
29
33
|
if TYPE_CHECKING:
|
|
30
34
|
from pydantic.fields import FieldInfo
|
|
@@ -42,6 +46,7 @@ logger = logging.getLogger(__name__)
|
|
|
42
46
|
CONTENT_DISPOSITION_NAME_PARAM = "name="
|
|
43
47
|
APPLICATION_JSON_CONTENT_TYPE = "application/json"
|
|
44
48
|
APPLICATION_FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"
|
|
49
|
+
MULTIPART_FORM_DATA_CONTENT_TYPE = "multipart/form-data"
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
class OpenAPIRequestValidationMiddleware(BaseMiddlewareHandler):
|
|
@@ -94,10 +99,17 @@ class OpenAPIRequestValidationMiddleware(BaseMiddlewareHandler):
|
|
|
94
99
|
headers,
|
|
95
100
|
)
|
|
96
101
|
|
|
102
|
+
# Process cookie values
|
|
103
|
+
cookie_values, cookie_errors = _request_params_to_args(
|
|
104
|
+
route.dependant.cookie_params,
|
|
105
|
+
app.current_event.resolved_cookies_field,
|
|
106
|
+
)
|
|
107
|
+
|
|
97
108
|
values.update(path_values)
|
|
98
109
|
values.update(query_values)
|
|
99
110
|
values.update(header_values)
|
|
100
|
-
|
|
111
|
+
values.update(cookie_values)
|
|
112
|
+
errors += path_errors + query_errors + header_errors + cookie_errors
|
|
101
113
|
|
|
102
114
|
# Process the request body, if it exists
|
|
103
115
|
if route.dependant.body_params:
|
|
@@ -132,14 +144,18 @@ class OpenAPIRequestValidationMiddleware(BaseMiddlewareHandler):
|
|
|
132
144
|
elif content_type.startswith(APPLICATION_FORM_CONTENT_TYPE):
|
|
133
145
|
return self._parse_form_data(app)
|
|
134
146
|
|
|
147
|
+
# Handle multipart/form-data (file uploads)
|
|
148
|
+
elif content_type.startswith(MULTIPART_FORM_DATA_CONTENT_TYPE):
|
|
149
|
+
return self._parse_multipart_data(app, content_type)
|
|
150
|
+
|
|
135
151
|
else:
|
|
136
152
|
raise RequestUnsupportedContentType(
|
|
137
|
-
"
|
|
153
|
+
"Unsupported content type",
|
|
138
154
|
errors=[
|
|
139
155
|
{
|
|
140
156
|
"type": "unsupported_content_type",
|
|
141
157
|
"loc": ("body",),
|
|
142
|
-
"msg": "
|
|
158
|
+
"msg": f"Unsupported content type: {content_type}",
|
|
143
159
|
"input": {},
|
|
144
160
|
"ctx": {},
|
|
145
161
|
},
|
|
@@ -186,6 +202,49 @@ class OpenAPIRequestValidationMiddleware(BaseMiddlewareHandler):
|
|
|
186
202
|
],
|
|
187
203
|
) from e
|
|
188
204
|
|
|
205
|
+
def _parse_multipart_data(self, app: EventHandlerInstance, content_type: str) -> dict[str, Any]:
|
|
206
|
+
"""Parse multipart/form-data from the request body (file uploads)."""
|
|
207
|
+
try:
|
|
208
|
+
# Extract the boundary from the content-type header
|
|
209
|
+
boundary = _extract_multipart_boundary(content_type)
|
|
210
|
+
if not boundary:
|
|
211
|
+
raise ValueError("Missing boundary in multipart/form-data content-type header")
|
|
212
|
+
|
|
213
|
+
# Get raw body bytes
|
|
214
|
+
raw_body = app.current_event.body or ""
|
|
215
|
+
if app.current_event.is_base64_encoded:
|
|
216
|
+
body_bytes = base64.b64decode(raw_body)
|
|
217
|
+
else:
|
|
218
|
+
warnings.warn(
|
|
219
|
+
"Received multipart/form-data without base64 encoding. "
|
|
220
|
+
"Binary file uploads may be corrupted. "
|
|
221
|
+
"If using API Gateway REST API (v1), configure Binary Media Types "
|
|
222
|
+
"to include 'multipart/form-data'. "
|
|
223
|
+
"See: https://docs.aws.amazon.com/apigateway/latest/developerguide/"
|
|
224
|
+
"api-gateway-payload-encodings.html",
|
|
225
|
+
stacklevel=2,
|
|
226
|
+
)
|
|
227
|
+
# Use latin-1 to preserve all byte values (0-255) since the body
|
|
228
|
+
# may contain raw binary data that isn't valid UTF-8
|
|
229
|
+
body_bytes = raw_body.encode("latin-1")
|
|
230
|
+
|
|
231
|
+
return _parse_multipart_body(body_bytes, boundary)
|
|
232
|
+
|
|
233
|
+
except ValueError:
|
|
234
|
+
raise
|
|
235
|
+
except Exception as e:
|
|
236
|
+
raise RequestValidationError(
|
|
237
|
+
[
|
|
238
|
+
{
|
|
239
|
+
"type": "multipart_invalid",
|
|
240
|
+
"loc": ("body",),
|
|
241
|
+
"msg": "Multipart form data parsing error",
|
|
242
|
+
"input": {},
|
|
243
|
+
"ctx": {"error": str(e)},
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
) from e
|
|
247
|
+
|
|
189
248
|
|
|
190
249
|
class OpenAPIResponseValidationMiddleware(BaseMiddlewareHandler):
|
|
191
250
|
"""
|
|
@@ -389,7 +448,12 @@ def _request_body_to_args(
|
|
|
389
448
|
continue
|
|
390
449
|
|
|
391
450
|
value = _normalize_field_value(value=value, field_info=field.field_info)
|
|
392
|
-
|
|
451
|
+
|
|
452
|
+
# UploadFile objects bypass Pydantic validation — they're already constructed
|
|
453
|
+
if isinstance(value, UploadFile):
|
|
454
|
+
values[field.name] = value
|
|
455
|
+
else:
|
|
456
|
+
values[field.name] = _validate_field(field=field, value=value, loc=loc, existing_errors=errors)
|
|
393
457
|
|
|
394
458
|
return values, errors
|
|
395
459
|
|
|
@@ -431,9 +495,45 @@ def _handle_missing_field_value(
|
|
|
431
495
|
values[field.name] = field.get_default()
|
|
432
496
|
|
|
433
497
|
|
|
498
|
+
def _is_or_contains_sequence(annotation: Any) -> bool:
|
|
499
|
+
"""
|
|
500
|
+
Check if annotation is a sequence or Union/RootModel containing a sequence.
|
|
501
|
+
|
|
502
|
+
This function handles complex type annotations like:
|
|
503
|
+
- List[Model] - direct sequence
|
|
504
|
+
- Union[Model, List[Model]] - checks if any Union member is a sequence
|
|
505
|
+
- Optional[List[Model]] - Union[List[Model], None]
|
|
506
|
+
- RootModel[List[Model]] - checks if the RootModel wraps a sequence
|
|
507
|
+
- Optional[RootModel[List[Model]]] - Union member that is a RootModel
|
|
508
|
+
- RootModel[Union[Model, List[Model]]] - RootModel wrapping a Union with a sequence
|
|
509
|
+
"""
|
|
510
|
+
# Direct sequence check
|
|
511
|
+
if field_annotation_is_sequence(annotation):
|
|
512
|
+
return True
|
|
513
|
+
|
|
514
|
+
# Check Union members — recurse so we catch RootModel inside Union
|
|
515
|
+
origin = get_origin(annotation)
|
|
516
|
+
if origin is Union or origin is UnionType:
|
|
517
|
+
for arg in get_args(annotation):
|
|
518
|
+
if _is_or_contains_sequence(arg):
|
|
519
|
+
return True
|
|
520
|
+
|
|
521
|
+
# Check if it's a RootModel wrapping a sequence (or Union containing a sequence)
|
|
522
|
+
if lenient_issubclass(annotation, BaseModel) and getattr(annotation, "__pydantic_root_model__", False):
|
|
523
|
+
if hasattr(annotation, "model_fields") and "root" in annotation.model_fields:
|
|
524
|
+
root_annotation = annotation.model_fields["root"].annotation
|
|
525
|
+
return _is_or_contains_sequence(root_annotation)
|
|
526
|
+
|
|
527
|
+
return False
|
|
528
|
+
|
|
529
|
+
|
|
434
530
|
def _normalize_field_value(value: Any, field_info: FieldInfo) -> Any:
|
|
435
531
|
"""Normalize field value, converting lists to single values for non-sequence fields."""
|
|
436
|
-
|
|
532
|
+
# When annotation is bytes but value is UploadFile, extract raw content
|
|
533
|
+
if isinstance(value, UploadFile) and field_info.annotation is bytes:
|
|
534
|
+
return value.content
|
|
535
|
+
|
|
536
|
+
if _is_or_contains_sequence(field_info.annotation):
|
|
437
537
|
return value
|
|
438
538
|
elif isinstance(value, list) and value:
|
|
439
539
|
return value[0]
|
|
@@ -546,3 +646,106 @@ def _get_param_value(
|
|
|
546
646
|
value = input_dict.get(field_name)
|
|
547
647
|
|
|
548
648
|
return value
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def _extract_multipart_boundary(content_type: str) -> str | None:
|
|
652
|
+
"""Extract the boundary string from a multipart/form-data content-type header."""
|
|
653
|
+
for segment in content_type.split(";"):
|
|
654
|
+
stripped = segment.strip()
|
|
655
|
+
if stripped.startswith("boundary="):
|
|
656
|
+
boundary = stripped[len("boundary=") :]
|
|
657
|
+
# Remove optional quotes around boundary
|
|
658
|
+
if boundary.startswith('"') and boundary.endswith('"'):
|
|
659
|
+
boundary = boundary[1:-1]
|
|
660
|
+
return boundary
|
|
661
|
+
return None
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def _parse_multipart_body(body: bytes, boundary: str) -> dict[str, Any]:
|
|
665
|
+
"""
|
|
666
|
+
Parse a multipart/form-data body into a dict of field names to values.
|
|
667
|
+
|
|
668
|
+
File fields get bytes values; regular form fields get string values.
|
|
669
|
+
Multiple values for the same field name are collected into lists.
|
|
670
|
+
"""
|
|
671
|
+
delimiter = f"--{boundary}".encode()
|
|
672
|
+
end_delimiter = f"--{boundary}--".encode()
|
|
673
|
+
|
|
674
|
+
result: dict[str, Any] = {}
|
|
675
|
+
|
|
676
|
+
# Split body by the boundary delimiter
|
|
677
|
+
raw_parts = body.split(delimiter)
|
|
678
|
+
|
|
679
|
+
for raw_part in raw_parts:
|
|
680
|
+
# Skip the preamble (before first boundary) and epilogue (after closing boundary)
|
|
681
|
+
if not raw_part or raw_part.strip() == b"" or raw_part.strip() == b"--":
|
|
682
|
+
continue
|
|
683
|
+
|
|
684
|
+
# Remove the end delimiter marker if present
|
|
685
|
+
chunk = raw_part
|
|
686
|
+
if chunk.endswith(end_delimiter):
|
|
687
|
+
chunk = chunk[: -len(end_delimiter)]
|
|
688
|
+
|
|
689
|
+
# Strip leading \r\n
|
|
690
|
+
if chunk.startswith(b"\r\n"):
|
|
691
|
+
chunk = chunk[2:]
|
|
692
|
+
|
|
693
|
+
# Strip trailing \r\n
|
|
694
|
+
if chunk.endswith(b"\r\n"):
|
|
695
|
+
chunk = chunk[:-2]
|
|
696
|
+
|
|
697
|
+
# Split headers from body at the double CRLF
|
|
698
|
+
header_end = chunk.find(b"\r\n\r\n")
|
|
699
|
+
if header_end == -1:
|
|
700
|
+
continue
|
|
701
|
+
|
|
702
|
+
header_section = chunk[:header_end].decode("utf-8")
|
|
703
|
+
body_section = chunk[header_end + 4 :]
|
|
704
|
+
|
|
705
|
+
# Parse Content-Disposition to get the field name and optional filename
|
|
706
|
+
field_name = None
|
|
707
|
+
filename = None
|
|
708
|
+
content_type_header = None
|
|
709
|
+
|
|
710
|
+
for header_line in header_section.split("\r\n"):
|
|
711
|
+
header_lower = header_line.lower()
|
|
712
|
+
if header_lower.startswith("content-disposition:"):
|
|
713
|
+
field_name = _extract_header_param(header_line, "name")
|
|
714
|
+
filename = _extract_header_param(header_line, "filename")
|
|
715
|
+
elif header_lower.startswith("content-type:"):
|
|
716
|
+
content_type_header = header_line.split(":", 1)[1].strip()
|
|
717
|
+
|
|
718
|
+
if field_name is None:
|
|
719
|
+
continue
|
|
720
|
+
|
|
721
|
+
# If it has a filename, it's a file upload — wrap as UploadFile
|
|
722
|
+
# Otherwise it's a regular form field — decode to string
|
|
723
|
+
if filename is not None:
|
|
724
|
+
value: Any = UploadFile(content=body_section, filename=filename, content_type=content_type_header)
|
|
725
|
+
else:
|
|
726
|
+
value = body_section.decode("utf-8")
|
|
727
|
+
|
|
728
|
+
# Collect multiple values for same field name into a list
|
|
729
|
+
if field_name in result:
|
|
730
|
+
existing = result[field_name]
|
|
731
|
+
if isinstance(existing, list):
|
|
732
|
+
existing.append(value)
|
|
733
|
+
else:
|
|
734
|
+
result[field_name] = [existing, value]
|
|
735
|
+
else:
|
|
736
|
+
result[field_name] = value
|
|
737
|
+
|
|
738
|
+
return result
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
def _extract_header_param(header_line: str, param_name: str) -> str | None:
|
|
742
|
+
"""Extract a parameter value from a header line (e.g., name="file" from Content-Disposition)."""
|
|
743
|
+
search = f'{param_name}="'
|
|
744
|
+
idx = header_line.find(search)
|
|
745
|
+
if idx == -1:
|
|
746
|
+
return None
|
|
747
|
+
start = idx + len(search)
|
|
748
|
+
end = header_line.find('"', start)
|
|
749
|
+
if end == -1:
|
|
750
|
+
return None
|
|
751
|
+
return header_line[start:end]
|
|
@@ -13,15 +13,16 @@ from aws_lambda_powertools.event_handler.openapi.compat import (
|
|
|
13
13
|
from aws_lambda_powertools.event_handler.openapi.params import (
|
|
14
14
|
Body,
|
|
15
15
|
Dependant,
|
|
16
|
+
File,
|
|
16
17
|
Form,
|
|
17
18
|
Param,
|
|
18
19
|
ParamTypes,
|
|
19
|
-
_File,
|
|
20
20
|
analyze_param,
|
|
21
21
|
create_response_field,
|
|
22
22
|
get_flat_dependant,
|
|
23
23
|
)
|
|
24
24
|
from aws_lambda_powertools.event_handler.openapi.types import OpenAPIResponse, OpenAPIResponseContentModel
|
|
25
|
+
from aws_lambda_powertools.event_handler.request import Request
|
|
25
26
|
|
|
26
27
|
if TYPE_CHECKING:
|
|
27
28
|
from collections.abc import Callable
|
|
@@ -187,6 +188,11 @@ def get_dependant(
|
|
|
187
188
|
|
|
188
189
|
# Add each parameter to the dependant model
|
|
189
190
|
for param_name, param in signature_params.items():
|
|
191
|
+
# Request-typed parameters are injected by the resolver at call time;
|
|
192
|
+
# they carry no OpenAPI meaning and must be excluded from schema generation.
|
|
193
|
+
if param.annotation is Request:
|
|
194
|
+
continue
|
|
195
|
+
|
|
190
196
|
# If the parameter is a path parameter, we need to set the in_ field to "path".
|
|
191
197
|
is_path_param = param_name in path_param_names
|
|
192
198
|
|
|
@@ -364,9 +370,9 @@ def get_body_field_info(
|
|
|
364
370
|
if not required:
|
|
365
371
|
body_field_info_kwargs["default"] = None
|
|
366
372
|
|
|
367
|
-
if any(isinstance(f.field_info,
|
|
368
|
-
|
|
369
|
-
|
|
373
|
+
if any(isinstance(f.field_info, File) for f in flat_dependant.body_params):
|
|
374
|
+
body_field_info = Body
|
|
375
|
+
body_field_info_kwargs["media_type"] = "multipart/form-data"
|
|
370
376
|
elif any(isinstance(f.field_info, Form) for f in flat_dependant.body_params):
|
|
371
377
|
body_field_info = Body
|
|
372
378
|
body_field_info_kwargs["media_type"] = "application/x-www-form-urlencoded"
|
|
@@ -67,11 +67,18 @@ def _file_has_resolver(file_path: Path, resolver_name: str) -> bool:
|
|
|
67
67
|
return False
|
|
68
68
|
|
|
69
69
|
for node in ast.walk(tree):
|
|
70
|
+
targets: list[ast.expr] = []
|
|
71
|
+
value: ast.expr | None = None
|
|
70
72
|
if isinstance(node, ast.Assign):
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
targets = node.targets
|
|
74
|
+
value = node.value
|
|
75
|
+
elif isinstance(node, ast.AnnAssign):
|
|
76
|
+
targets = [node.target]
|
|
77
|
+
value = node.value
|
|
78
|
+
for target in targets:
|
|
79
|
+
if isinstance(target, ast.Name) and target.id == resolver_name:
|
|
80
|
+
if value is not None and _is_resolver_call(value):
|
|
81
|
+
return True
|
|
75
82
|
return False
|
|
76
83
|
|
|
77
84
|
|