aws-lambda-powertools 3.30.0__tar.gz → 3.31.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.
Files changed (320) hide show
  1. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/PKG-INFO +2 -2
  2. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/params.py +45 -43
  3. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/constants.py +3 -0
  4. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/version.py +1 -1
  5. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/__init__.py +35 -0
  6. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/base.py +248 -0
  7. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/circuit_breaker.py +119 -0
  8. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/config.py +128 -0
  9. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/exceptions.py +77 -0
  10. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/__init__.py +15 -0
  11. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/base.py +291 -0
  12. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/dynamodb.py +252 -0
  13. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/persistence/record.py +63 -0
  14. aws_lambda_powertools-3.31.0/aws_lambda_powertools/utilities/circuit_breaker_alpha/states.py +126 -0
  15. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/pyproject.toml +2 -2
  16. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/setup.py +4 -2
  17. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/LICENSE +0 -0
  18. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/README.md +0 -0
  19. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/THIRD-PARTY-LICENSES +0 -0
  20. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/__init__.py +0 -0
  21. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/__init__.py +0 -0
  22. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/api_gateway.py +0 -0
  23. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/appsync.py +0 -0
  24. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/bedrock_agent.py +0 -0
  25. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/bedrock_agent_function.py +0 -0
  26. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/content_types.py +0 -0
  27. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/depends.py +0 -0
  28. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/__init__.py +0 -0
  29. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/_registry.py +0 -0
  30. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/appsync_events.py +0 -0
  31. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/base.py +0 -0
  32. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/exceptions.py +0 -0
  33. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/functions.py +0 -0
  34. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/router.py +0 -0
  35. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/events_appsync/types.py +0 -0
  36. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/exception_handling.py +0 -0
  37. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/exceptions.py +0 -0
  38. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/__init__.py +0 -0
  39. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/_registry.py +0 -0
  40. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/base.py +0 -0
  41. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/exceptions.py +0 -0
  42. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/graphql_appsync/router.py +0 -0
  43. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/http_resolver.py +0 -0
  44. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/lambda_function_url.py +0 -0
  45. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/__init__.py +0 -0
  46. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/async_utils.py +0 -0
  47. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/base.py +0 -0
  48. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py +0 -0
  49. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/middlewares/schema_validation.py +0 -0
  50. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/__init__.py +0 -0
  51. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/compat.py +0 -0
  52. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/config.py +0 -0
  53. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/constants.py +0 -0
  54. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/dependant.py +0 -0
  55. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/encoders.py +0 -0
  56. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/exceptions.py +0 -0
  57. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/merge.py +0 -0
  58. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/models.py +0 -0
  59. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/pydantic_loader.py +0 -0
  60. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/schema_generator.py +0 -0
  61. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/__init__.py +0 -0
  62. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/html.py +0 -0
  63. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/oauth2.py +0 -0
  64. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui-bundle.min.js +0 -0
  65. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/swagger_ui/swagger-ui.min.css +0 -0
  66. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/openapi/types.py +0 -0
  67. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/request.py +0 -0
  68. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/router.py +0 -0
  69. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/types.py +0 -0
  70. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/util.py +0 -0
  71. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/event_handler/vpc_lattice.py +0 -0
  72. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/exceptions/__init__.py +0 -0
  73. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/__init__.py +0 -0
  74. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/__init__.py +0 -0
  75. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/cache.py +0 -0
  76. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/config.py +0 -0
  77. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/functions.py +0 -0
  78. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/buffer/handler.py +0 -0
  79. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/constants.py +0 -0
  80. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/correlation_paths.py +0 -0
  81. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/exceptions.py +0 -0
  82. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/filters.py +0 -0
  83. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatter.py +0 -0
  84. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatters/__init__.py +0 -0
  85. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/formatters/datadog.py +0 -0
  86. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/lambda_context.py +0 -0
  87. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/logger.py +0 -0
  88. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/types.py +0 -0
  89. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/logging/utils.py +0 -0
  90. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/__init__.py +0 -0
  91. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/base.py +0 -0
  92. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/exceptions.py +0 -0
  93. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/functions.py +0 -0
  94. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/metric.py +0 -0
  95. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/metrics.py +0 -0
  96. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/__init__.py +0 -0
  97. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/base.py +0 -0
  98. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/__init__.py +0 -0
  99. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +0 -0
  100. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/constants.py +0 -0
  101. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/exceptions.py +0 -0
  102. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/metric_properties.py +0 -0
  103. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cloudwatch_emf/types.py +0 -0
  104. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/cold_start.py +0 -0
  105. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/__init__.py +0 -0
  106. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/datadog.py +0 -0
  107. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/metrics.py +0 -0
  108. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/provider/datadog/warnings.py +0 -0
  109. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/metrics/types.py +0 -0
  110. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/__init__.py +0 -0
  111. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/exceptions.py +0 -0
  112. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/middleware_factory/factory.py +0 -0
  113. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/package_logger.py +0 -0
  114. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/py.typed +0 -0
  115. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/__init__.py +0 -0
  116. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/cache_dict.py +0 -0
  117. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/cookies.py +0 -0
  118. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/dynamodb_deserializer.py +0 -0
  119. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/functions.py +0 -0
  120. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/headers_serializer.py +0 -0
  121. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/json_encoder.py +0 -0
  122. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/lazy_import.py +0 -0
  123. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/types.py +0 -0
  124. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/shared/user_agent.py +0 -0
  125. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/__init__.py +0 -0
  126. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/base.py +0 -0
  127. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/extensions.py +0 -0
  128. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/tracing/tracer.py +0 -0
  129. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/__init__.py +0 -0
  130. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/__init__.py +0 -0
  131. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/base.py +0 -0
  132. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/decorators.py +0 -0
  133. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/exceptions.py +0 -0
  134. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/sqs_fifo_partial_processor.py +0 -0
  135. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/batch/types.py +0 -0
  136. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/__init__.py +0 -0
  137. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/active_mq_event.py +0 -0
  138. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/alb_event.py +0 -0
  139. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py +0 -0
  140. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py +0 -0
  141. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/api_gateway_websocket_event.py +0 -0
  142. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync/__init__.py +0 -0
  143. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync/scalar_types_utils.py +0 -0
  144. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py +0 -0
  145. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py +0 -0
  146. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/appsync_resolver_events_event.py +0 -0
  147. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py +0 -0
  148. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_event.py +0 -0
  149. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/bedrock_agent_function_event.py +0 -0
  150. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_alarm_event.py +0 -0
  151. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_custom_widget_event.py +0 -0
  152. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py +0 -0
  153. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cloudformation_custom_resource_event.py +0 -0
  154. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/code_deploy_lifecycle_hook_event.py +0 -0
  155. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py +0 -0
  156. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py +0 -0
  157. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/common.py +0 -0
  158. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py +0 -0
  159. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py +0 -0
  160. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/event_bridge_event.py +0 -0
  161. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/event_source.py +0 -0
  162. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/iot_registry_event.py +0 -0
  163. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kafka_event.py +0 -0
  164. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py +0 -0
  165. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py +0 -0
  166. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/lambda_function_url_event.py +0 -0
  167. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py +0 -0
  168. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_batch_operation_event.py +0 -0
  169. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_event.py +0 -0
  170. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/s3_object_event.py +0 -0
  171. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/secrets_manager_event.py +0 -0
  172. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/ses_event.py +0 -0
  173. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/shared_functions.py +0 -0
  174. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/sns_event.py +0 -0
  175. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/sqs_event.py +0 -0
  176. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/transfer_family_event.py +0 -0
  177. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_classes/vpc_lattice.py +0 -0
  178. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/__init__.py +0 -0
  179. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/base.py +0 -0
  180. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/constants.py +0 -0
  181. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/exceptions.py +0 -0
  182. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/__init__.py +0 -0
  183. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/base.py +0 -0
  184. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/__init__.py +0 -0
  185. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/data_masking/provider/kms/aws_encryption_sdk.py +0 -0
  186. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/__init__.py +0 -0
  187. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/appconfig.py +0 -0
  188. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/base.py +0 -0
  189. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/comparators.py +0 -0
  190. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/constants.py +0 -0
  191. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/exceptions.py +0 -0
  192. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/feature_flags.py +0 -0
  193. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/schema.py +0 -0
  194. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/feature_flags/types.py +0 -0
  195. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/__init__.py +0 -0
  196. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/base.py +0 -0
  197. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/config.py +0 -0
  198. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/exceptions.py +0 -0
  199. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/hook.py +0 -0
  200. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/idempotency.py +0 -0
  201. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/__init__.py +0 -0
  202. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/base.py +0 -0
  203. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/cache.py +0 -0
  204. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/datarecord.py +0 -0
  205. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py +0 -0
  206. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/persistence/redis.py +0 -0
  207. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/__init__.py +0 -0
  208. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/base.py +0 -0
  209. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/custom_dict.py +0 -0
  210. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/dataclass.py +0 -0
  211. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/functions.py +0 -0
  212. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/no_op.py +0 -0
  213. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/idempotency/serialization/pydantic.py +0 -0
  214. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/jmespath_utils/__init__.py +0 -0
  215. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/jmespath_utils/envelopes.py +0 -0
  216. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/__init__.py +0 -0
  217. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/consumer_records.py +0 -0
  218. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/__init__.py +0 -0
  219. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/avro.py +0 -0
  220. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/base.py +0 -0
  221. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/default.py +0 -0
  222. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/deserializer.py +0 -0
  223. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/json.py +0 -0
  224. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/deserializer/protobuf.py +0 -0
  225. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/exceptions.py +0 -0
  226. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/kafka_consumer.py +0 -0
  227. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/schema_config.py +0 -0
  228. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/__init__.py +0 -0
  229. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/base.py +0 -0
  230. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/custom_dict.py +0 -0
  231. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/dataclass.py +0 -0
  232. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/pydantic.py +0 -0
  233. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/serialization.py +0 -0
  234. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/kafka/serialization/types.py +0 -0
  235. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/__init__.py +0 -0
  236. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/exceptions.py +0 -0
  237. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/metadata/lambda_metadata.py +0 -0
  238. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/__init__.py +0 -0
  239. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/appconfig.py +0 -0
  240. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/base.py +0 -0
  241. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/constants.py +0 -0
  242. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/dynamodb.py +0 -0
  243. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/exceptions.py +0 -0
  244. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/secrets.py +0 -0
  245. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/ssm.py +0 -0
  246. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parameters/types.py +0 -0
  247. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/__init__.py +0 -0
  248. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/__init__.py +0 -0
  249. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw.py +0 -0
  250. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigw_websocket.py +0 -0
  251. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py +0 -0
  252. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/base.py +0 -0
  253. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/bedrock_agent.py +0 -0
  254. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py +0 -0
  255. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py +0 -0
  256. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py +0 -0
  257. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kafka.py +0 -0
  258. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis.py +0 -0
  259. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/kinesis_firehose.py +0 -0
  260. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py +0 -0
  261. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/sns.py +0 -0
  262. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/sqs.py +0 -0
  263. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_lattice.py +0 -0
  264. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/envelopes/vpc_latticev2.py +0 -0
  265. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/exceptions.py +0 -0
  266. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/functions.py +0 -0
  267. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/__init__.py +0 -0
  268. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/alb.py +0 -0
  269. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigw.py +0 -0
  270. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigw_websocket.py +0 -0
  271. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/apigwv2.py +0 -0
  272. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/appsync.py +0 -0
  273. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/appsync_events.py +0 -0
  274. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/bedrock_agent.py +0 -0
  275. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cloudformation_custom_resource.py +0 -0
  276. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cloudwatch.py +0 -0
  277. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/cognito.py +0 -0
  278. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/dynamodb.py +0 -0
  279. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/event_bridge.py +0 -0
  280. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/iot_registry_events.py +0 -0
  281. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kafka.py +0 -0
  282. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis.py +0 -0
  283. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose.py +0 -0
  284. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/kinesis_firehose_sqs.py +0 -0
  285. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/lambda_function_url.py +0 -0
  286. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3.py +0 -0
  287. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_batch_operation.py +0 -0
  288. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_event_notification.py +0 -0
  289. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/s3_object_event.py +0 -0
  290. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/ses.py +0 -0
  291. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/sns.py +0 -0
  292. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/sqs.py +0 -0
  293. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/transfer_family.py +0 -0
  294. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/vpc_lattice.py +0 -0
  295. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/models/vpc_latticev2.py +0 -0
  296. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/parser.py +0 -0
  297. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/parser/types.py +0 -0
  298. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/serialization.py +0 -0
  299. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/__init__.py +0 -0
  300. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/_s3_seekable_io.py +0 -0
  301. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/compat.py +0 -0
  302. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/constants.py +0 -0
  303. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/s3_object.py +0 -0
  304. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/__init__.py +0 -0
  305. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/base.py +0 -0
  306. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/csv.py +0 -0
  307. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/gzip.py +0 -0
  308. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/transformations/zip.py +0 -0
  309. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/streaming/types.py +0 -0
  310. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/__init__.py +0 -0
  311. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_client_context.py +0 -0
  312. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_client_context_mobile_client.py +0 -0
  313. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_cognito_identity.py +0 -0
  314. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/typing/lambda_context.py +0 -0
  315. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/__init__.py +0 -0
  316. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/base.py +0 -0
  317. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/envelopes.py +0 -0
  318. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/exceptions.py +0 -0
  319. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.0}/aws_lambda_powertools/utilities/validation/validator.py +0 -0
  320. {aws_lambda_powertools-3.30.0 → aws_lambda_powertools-3.31.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.30.0
3
+ Version: 3.31.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
@@ -39,7 +39,7 @@ Requires-Dist: jsonpath-ng (>=1.6.0,<2.0.0) ; extra == "all" or extra == "datama
39
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
- Requires-Dist: redis (>=4.4,<8.0) ; extra == "redis"
42
+ Requires-Dist: redis (>=4.4,<9.0) ; extra == "redis"
43
43
  Requires-Dist: typing-extensions (>=4.11.0,<5.0.0)
44
44
  Requires-Dist: valkey-glide (>=1.3.5,<3.0) ; extra == "valkey"
45
45
  Project-URL: Documentation, https://docs.powertools.aws.dev/lambda/python/
@@ -953,54 +953,52 @@ def get_field_info_response_type(annotation, value) -> tuple[FieldInfo | None, A
953
953
  return get_field_info_and_type_annotation(inner_type, value, False, True)
954
954
 
955
955
 
956
- def _has_discriminator(field_info: FieldInfo) -> bool:
957
- """Check if a FieldInfo has a discriminator."""
958
- return hasattr(field_info, "discriminator") and field_info.discriminator is not None
959
-
960
-
961
- def _handle_discriminator_with_param(
956
+ def _split_location_marker_and_field(
962
957
  annotations: list[FieldInfo],
963
- annotation: Any,
964
- ) -> tuple[FieldInfo | None, Any, bool]:
958
+ ) -> tuple[FieldInfo, FieldInfo]:
965
959
  """
966
- Handle the special case of Field(discriminator) + Body() combination.
960
+ Split a pair of FieldInfo into the Powertools location marker and the plain Pydantic Field.
961
+
962
+ A parameter like ``Annotated[str, Field(gt=0), Query()]`` flattens to two FieldInfo: the
963
+ location marker (``Path``/``Query``/``Header``/``Body``, a ``Param`` or ``Body`` subclass) and
964
+ a plain Pydantic ``Field`` carrying constraints. We keep them apart so the location marker
965
+ drives where the value comes from, while the ``Field``'s constraints/metadata still apply.
967
966
 
968
967
  Returns:
969
- tuple of (powertools_annotation, type_annotation, has_discriminator_with_body)
968
+ tuple of (location_marker, plain_field)
970
969
  """
971
- field_obj = None
972
- body_obj = None
970
+ location_marker: FieldInfo | None = None
971
+ plain_field: FieldInfo | None = None
973
972
 
974
973
  for ann in annotations:
975
- if isinstance(ann, Body):
976
- body_obj = ann
977
- elif _has_discriminator(ann):
978
- field_obj = ann
974
+ if isinstance(ann, (Param, Body)):
975
+ location_marker = ann
976
+ else:
977
+ plain_field = ann
979
978
 
980
- if field_obj and body_obj:
981
- # Use Body as the primary annotation, preserve full annotation for validation
982
- return body_obj, annotation, True
979
+ if location_marker is None or plain_field is None:
980
+ raise AssertionError("Only one FieldInfo can be used per parameter")
983
981
 
984
- raise AssertionError("Only one FieldInfo can be used per parameter")
982
+ return location_marker, plain_field
985
983
 
986
984
 
987
985
  def _create_field_info(
988
986
  powertools_annotation: FieldInfo,
989
987
  type_annotation: Any,
990
- has_discriminator_with_body: bool,
988
+ preserve_full_annotation: bool,
991
989
  ) -> FieldInfo:
992
990
  """Create or copy FieldInfo based on the annotation type."""
993
- field_info: FieldInfo
994
- if has_discriminator_with_body:
995
- # For discriminator + Body case, create a new Body instance directly
996
- field_info = Body()
991
+ # Copy field_info because we mutate field_info.default later.
992
+ field_info = copy_field_info(
993
+ field_info=powertools_annotation,
994
+ annotation=type_annotation,
995
+ )
996
+ if preserve_full_annotation:
997
+ # The location marker is paired with a plain Field (constraints or discriminator).
998
+ # copy_field_info strips the Pydantic Field out of the metadata, so re-attach the full
999
+ # Annotated type here, that's what makes the Field's metadata flow into the TypeAdapter
1000
+ # that ModelField builds for validation.
997
1001
  field_info.annotation = type_annotation
998
- else:
999
- # Copy field_info because we mutate field_info.default later
1000
- field_info = copy_field_info(
1001
- field_info=powertools_annotation,
1002
- annotation=type_annotation,
1003
- )
1004
1002
  return field_info
1005
1003
 
1006
1004
 
@@ -1043,13 +1041,16 @@ def get_field_info_annotated_type(annotation, value, is_path_param: bool) -> tup
1043
1041
 
1044
1042
  # Determine which annotation to use
1045
1043
  powertools_annotation: FieldInfo | None = None
1046
- has_discriminator_with_param = False
1044
+ # When a plain Pydantic Field is paired with a location marker (e.g. Field(gt=0) + Query),
1045
+ # we keep the full Annotated type as the annotation so the Field's metadata still validates.
1046
+ preserve_full_annotation = False
1047
1047
 
1048
1048
  if len(powertools_annotations) == 2:
1049
- powertools_annotation, type_annotation, has_discriminator_with_param = _handle_discriminator_with_param(
1050
- powertools_annotations,
1051
- annotation,
1052
- )
1049
+ # A location marker (Path/Query/Header/Body) plus a plain Pydantic Field carrying
1050
+ # constraints, a discriminator, or any other Field setting. The marker says where the
1051
+ # value comes from; the Field says how to validate it.
1052
+ powertools_annotation, _ = _split_location_marker_and_field(powertools_annotations)
1053
+ preserve_full_annotation = True
1053
1054
  elif len(powertools_annotations) > 1:
1054
1055
  raise AssertionError("Only one FieldInfo can be used per parameter")
1055
1056
  else:
@@ -1057,18 +1058,19 @@ def get_field_info_annotated_type(annotation, value, is_path_param: bool) -> tup
1057
1058
 
1058
1059
  # Reconstruct type_annotation with non-FieldInfo metadata if present
1059
1060
  # This ensures constraints like Interval are preserved
1060
- if other_metadata and not has_discriminator_with_param:
1061
+ if other_metadata and not preserve_full_annotation:
1061
1062
  type_annotation = Annotated[(type_annotation, *other_metadata)]
1062
1063
 
1063
1064
  # Process the annotation if it exists
1064
1065
  field_info: FieldInfo | None = None
1065
- if isinstance(powertools_annotation, FieldInfo): # pragma: no cover
1066
- field_info = _create_field_info(powertools_annotation, type_annotation, has_discriminator_with_param)
1066
+ if isinstance(powertools_annotation, FieldInfo):
1067
+ # When pairing a location marker with a plain Field, hand the full Annotated[...] to the
1068
+ # field so the Field's constraints/discriminator flow into the validating TypeAdapter.
1069
+ field_annotation = annotation if preserve_full_annotation else type_annotation
1070
+ field_info = _create_field_info(powertools_annotation, field_annotation, preserve_full_annotation)
1067
1071
  _set_field_default(field_info, value, is_path_param)
1068
-
1069
- # Preserve full annotated type for discriminated unions
1070
- if _has_discriminator(powertools_annotation): # pragma: no cover
1071
- type_annotation = annotation # pragma: no cover
1072
+ if preserve_full_annotation:
1073
+ type_annotation = annotation
1072
1074
 
1073
1075
  return field_info, type_annotation
1074
1076
 
@@ -76,3 +76,6 @@ METADATA_DEFAULT_TIMEOUT_SECS: float = 1.0
76
76
 
77
77
  # Idempotency constants
78
78
  IDEMPOTENCY_DISABLED_ENV: str = "POWERTOOLS_IDEMPOTENCY_DISABLED"
79
+
80
+ # Circuit breaker constants
81
+ CIRCUIT_BREAKER_DISABLED_ENV: str = "POWERTOOLS_CIRCUIT_BREAKER_DISABLED"
@@ -1,3 +1,3 @@
1
1
  """Exposes version constant to avoid circular dependencies."""
2
2
 
3
- VERSION = "3.30.0"
3
+ VERSION = "3.31.0"
@@ -0,0 +1,35 @@
1
+ """
2
+ Circuit Breaker utility for protecting unhealthy downstream dependencies.
3
+
4
+ !!! warning "Alpha / experimental"
5
+ This utility is published under the `_alpha` namespace while we collect
6
+ feedback. The public API may change in a backwards-incompatible way before it
7
+ is promoted to GA. Pin your version and follow the tracking discussion before
8
+ relying on it in production.
9
+ """
10
+
11
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.circuit_breaker import circuit_breaker
12
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
13
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.exceptions import (
14
+ CircuitBreakerConfigError,
15
+ CircuitBreakerError,
16
+ CircuitBreakerOpenError,
17
+ CircuitBreakerPersistenceError,
18
+ )
19
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import (
20
+ CircuitInfo,
21
+ CircuitState,
22
+ CircuitTransition,
23
+ )
24
+
25
+ __all__ = (
26
+ "circuit_breaker",
27
+ "CircuitBreakerConfig",
28
+ "CircuitInfo",
29
+ "CircuitState",
30
+ "CircuitTransition",
31
+ "CircuitBreakerError",
32
+ "CircuitBreakerOpenError",
33
+ "CircuitBreakerConfigError",
34
+ "CircuitBreakerPersistenceError",
35
+ )
@@ -0,0 +1,248 @@
1
+ """
2
+ Orchestrator for the Circuit Breaker utility.
3
+
4
+ :class:`CircuitBreakerHandler` owns the state machine and the per-environment failure
5
+ counter; the persistence layer owns the shared truth. This split keeps the healthy
6
+ path write-free: failures are counted locally and only persisted on a state transition.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import datetime
12
+ import logging
13
+ import uuid
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.exceptions import CircuitBreakerOpenError
17
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import CircuitState, CircuitTransition
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Callable
21
+
22
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
23
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence.base import (
24
+ CircuitBreakerPersistenceLayer,
25
+ )
26
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.states import CircuitInfo
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # Per-environment, per-circuit consecutive counters. Module-level so they survive across
31
+ # invocations within the same execution environment, the same way idempotency caches do.
32
+ _LOCAL_FAILURES: dict[str, int] = {}
33
+ _LOCAL_SUCCESSES: dict[str, int] = {}
34
+
35
+ # Tracks the last state this environment observed from the store, per circuit. Used to
36
+ # detect transitions back to CLOSED that happened externally (another env tripped and
37
+ # recovered), so stale local failure streaks can be invalidated.
38
+ _LAST_OBSERVED_STATE: dict[str, CircuitState] = {}
39
+
40
+ # Stable per-environment identifier used to claim the half-open probe lock.
41
+ _ENVIRONMENT_ID = uuid.uuid4().hex
42
+
43
+
44
+ class CircuitBreakerHandler:
45
+ """
46
+ Drive a single protected call through the circuit breaker state machine.
47
+
48
+ A new handler is created per invocation by the decorator. It reads the shared state,
49
+ routes the call (run, short-circuit, or probe), and records the outcome.
50
+
51
+ Parameters
52
+ ----------
53
+ function : Callable
54
+ The protected function.
55
+ name : str
56
+ Circuit name.
57
+ config : CircuitBreakerConfig
58
+ Circuit configuration.
59
+ persistence_store : CircuitBreakerPersistenceLayer
60
+ Shared state store.
61
+ on_circuit_open : Callable | None
62
+ Callback invoked with the protected call's own ``*args``/``**kwargs`` plus a
63
+ trailing ``circuit`` keyword argument when the circuit is open. If ``None``, an
64
+ open circuit raises :class:`CircuitBreakerOpenError`.
65
+ function_args : tuple
66
+ Positional arguments the protected function was called with.
67
+ function_kwargs : dict
68
+ Keyword arguments the protected function was called with.
69
+ """
70
+
71
+ def __init__(
72
+ self,
73
+ function: Callable,
74
+ name: str,
75
+ config: CircuitBreakerConfig,
76
+ persistence_store: CircuitBreakerPersistenceLayer,
77
+ on_circuit_open: Callable | None = None,
78
+ on_transition: Callable | None = None,
79
+ function_args: tuple | None = None,
80
+ function_kwargs: dict | None = None,
81
+ ):
82
+ self.function = function
83
+ self.name = name
84
+ self.config = config
85
+ self.on_circuit_open = on_circuit_open
86
+ self.on_transition = on_transition
87
+ self.fn_args = function_args or ()
88
+ self.fn_kwargs = function_kwargs or {}
89
+
90
+ persistence_store.configure(config=config, circuit_name=name)
91
+ self.persistence_store = persistence_store
92
+
93
+ def handle(self) -> Any:
94
+ """
95
+ Evaluate the circuit and route the call.
96
+
97
+ Returns
98
+ -------
99
+ Any
100
+ The protected function's result when the call runs, or the
101
+ ``on_circuit_open`` callback's return value when the circuit is open.
102
+
103
+ Raises
104
+ ------
105
+ CircuitBreakerOpenError
106
+ If the circuit is open and no callback is registered.
107
+ """
108
+ record = self.persistence_store.get_state(self.name)
109
+
110
+ if record.state == CircuitState.CLOSED:
111
+ # If we previously observed a non-CLOSED state and the circuit is now back to
112
+ # CLOSED, another environment completed the recovery cycle. Reset local counters
113
+ # so a stale partial failure streak doesn't immediately re-trip the circuit.
114
+ prev = _LAST_OBSERVED_STATE.get(self.name)
115
+ if prev is not None and prev != CircuitState.CLOSED:
116
+ _LOCAL_FAILURES[self.name] = 0
117
+ _LAST_OBSERVED_STATE[self.name] = CircuitState.CLOSED
118
+ return self._call_closed()
119
+
120
+ if record.state == CircuitState.OPEN:
121
+ _LAST_OBSERVED_STATE[self.name] = CircuitState.OPEN
122
+ # ``opened_at`` may legitimately be 0 (epoch); treat only None as missing.
123
+ opened_at = record.opened_at if record.opened_at is not None else self._now()
124
+ if self._now() >= opened_at + self.config.recovery_timeout:
125
+ # Recovery window elapsed: try to become the single prober.
126
+ if self.persistence_store.try_acquire_half_open(self.name, _ENVIRONMENT_ID, opened_at):
127
+ self._notify(CircuitState.OPEN, CircuitState.HALF_OPEN, opened_at=opened_at)
128
+ return self._call_probe()
129
+ return self._open_response(record.to_circuit_info())
130
+
131
+ # HALF_OPEN: only the environment that owns the probe lock runs.
132
+ _LAST_OBSERVED_STATE[self.name] = CircuitState.HALF_OPEN
133
+ if record.half_open_owner == _ENVIRONMENT_ID:
134
+ return self._call_probe()
135
+
136
+ # If the probe lease has expired (owner recycled mid-probe), take over.
137
+ if record.probe_lease_expiry is not None and self._now() >= record.probe_lease_expiry:
138
+ logger.debug("Circuit '%s' probe lease expired; attempting takeover.", self.name)
139
+ if self.persistence_store.try_acquire_half_open(self.name, _ENVIRONMENT_ID, record.opened_at or 0):
140
+ return self._call_probe()
141
+
142
+ return self._open_response(record.to_circuit_info())
143
+
144
+ def _call_closed(self) -> Any:
145
+ """Run the protected call while the circuit is closed, tracking failures."""
146
+ try:
147
+ result = self.function(*self.fn_args, **self.fn_kwargs)
148
+ except Exception as exc:
149
+ if not self.config.counts_as_failure(exc):
150
+ raise
151
+ failures = _LOCAL_FAILURES.get(self.name, 0) + 1
152
+ _LOCAL_FAILURES[self.name] = failures
153
+ if failures >= self.config.failure_threshold:
154
+ logger.debug("Circuit '%s' tripping CLOSED to OPEN after %d failures.", self.name, failures)
155
+ opened_at = self._now()
156
+ self._safe_persist(
157
+ self.persistence_store.save_open,
158
+ self.name,
159
+ failure_count=failures,
160
+ opened_at=opened_at,
161
+ )
162
+ _LOCAL_FAILURES[self.name] = 0
163
+ self._notify(CircuitState.CLOSED, CircuitState.OPEN, opened_at=opened_at)
164
+ raise
165
+ else:
166
+ _LOCAL_FAILURES[self.name] = 0
167
+ return result
168
+
169
+ def _call_probe(self) -> Any:
170
+ """Run a probe during half-open, closing or reopening based on the outcome."""
171
+ try:
172
+ result = self.function(*self.fn_args, **self.fn_kwargs)
173
+ except Exception as exc:
174
+ if not self.config.counts_as_failure(exc):
175
+ raise
176
+ logger.debug("Circuit '%s' probe failed; reopening.", self.name)
177
+ opened_at = self._now()
178
+ self._safe_persist(self.persistence_store.save_reopen, self.name, opened_at=opened_at)
179
+ _LOCAL_SUCCESSES[self.name] = 0
180
+ self._notify(CircuitState.HALF_OPEN, CircuitState.OPEN, opened_at=opened_at)
181
+ raise
182
+ else:
183
+ successes = _LOCAL_SUCCESSES.get(self.name, 0) + 1
184
+ _LOCAL_SUCCESSES[self.name] = successes
185
+ if successes >= self.config.success_threshold:
186
+ logger.debug("Circuit '%s' closing after %d probe successes.", self.name, successes)
187
+ self._safe_persist(self.persistence_store.save_closed, self.name)
188
+ _LOCAL_SUCCESSES[self.name] = 0
189
+ _LOCAL_FAILURES[self.name] = 0
190
+ self._notify(CircuitState.HALF_OPEN, CircuitState.CLOSED)
191
+ return result
192
+
193
+ def _safe_persist(self, fn: Callable, *args: Any, **kwargs: Any) -> None:
194
+ """
195
+ Call a persistence write, swallowing and logging failures.
196
+
197
+ State-transition writes must never mask the downstream's real result or replace
198
+ the downstream's real exception. This mirrors the fail-open read policy in the
199
+ persistence layer.
200
+ """
201
+ try:
202
+ fn(*args, **kwargs)
203
+ except Exception:
204
+ logger.warning(
205
+ "Circuit '%s': persistence write (%s) failed; the transition may be delayed but the "
206
+ "downstream result is preserved.",
207
+ self.name,
208
+ getattr(fn, "__name__", repr(fn)),
209
+ exc_info=True,
210
+ )
211
+
212
+ def _open_response(self, circuit: CircuitInfo) -> Any:
213
+ """Produce the response for an open circuit: callback result or raise."""
214
+ if self.on_circuit_open is not None:
215
+ # Forward the protected call's arguments unchanged: positional stay positional,
216
+ # keyword stay keyword. The circuit snapshot is passed as a keyword argument so
217
+ # it never collides with positionalized kwargs nor depends on dict ordering.
218
+ return self.on_circuit_open(*self.fn_args, **self.fn_kwargs, circuit=circuit)
219
+ raise CircuitBreakerOpenError(
220
+ f"Circuit '{self.name}' is open.",
221
+ circuit=circuit,
222
+ )
223
+
224
+ def _notify(self, from_state: CircuitState, to_state: CircuitState, opened_at: int | None = None) -> None:
225
+ """
226
+ Fire the ``on_transition`` hook for a state change.
227
+
228
+ Called only on real transitions, never on the hot path. Any exception the hook
229
+ raises is swallowed and logged: observability must never break the protected call.
230
+ """
231
+ if self.on_transition is None:
232
+ return
233
+ try:
234
+ self.on_transition(
235
+ CircuitTransition(
236
+ circuit_name=self.name,
237
+ from_state=from_state,
238
+ to_state=to_state,
239
+ opened_at=opened_at,
240
+ ),
241
+ )
242
+ except Exception:
243
+ logger.warning("on_transition hook for circuit '%s' raised; ignoring.", self.name, exc_info=True)
244
+
245
+ @staticmethod
246
+ def _now() -> int:
247
+ """Current unix timestamp in seconds."""
248
+ return int(datetime.datetime.now().timestamp())
@@ -0,0 +1,119 @@
1
+ """
2
+ Primary interface for the Circuit Breaker utility.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import functools
8
+ import logging
9
+ import os
10
+ import warnings
11
+ from typing import TYPE_CHECKING, Any
12
+
13
+ from aws_lambda_powertools.shared import constants
14
+ from aws_lambda_powertools.shared.functions import strtobool
15
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.base import CircuitBreakerHandler
16
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.config import CircuitBreakerConfig
17
+ from aws_lambda_powertools.warnings import PowertoolsUserWarning
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Callable
21
+
22
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence.base import (
23
+ CircuitBreakerPersistenceLayer,
24
+ )
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ def circuit_breaker(
30
+ name: str,
31
+ persistence_store: CircuitBreakerPersistenceLayer,
32
+ on_circuit_open: Callable | None = None,
33
+ on_transition: Callable | None = None,
34
+ config: CircuitBreakerConfig | None = None,
35
+ ) -> Callable:
36
+ """
37
+ Protect a function that calls an unhealthy-prone downstream with a circuit breaker.
38
+
39
+ Wrap the function that makes the downstream call, not the whole Lambda handler, so a
40
+ tripped circuit reflects one dependency rather than unrelated handler logic.
41
+
42
+ When the circuit is open the protected function is not called. Instead, if an
43
+ ``on_circuit_open`` callback is registered it runs and its return value becomes the
44
+ call's result; otherwise :class:`CircuitBreakerOpenError` is raised.
45
+
46
+ Parameters
47
+ ----------
48
+ name : str
49
+ Unique circuit name. Each name is an independent circuit; a function calling
50
+ several backends should use one circuit per backend.
51
+ persistence_store : CircuitBreakerPersistenceLayer
52
+ Shared state store (for example ``CircuitBreakerDynamoDBPersistence``).
53
+ on_circuit_open : Callable | None
54
+ Called when the circuit is open, with the protected function's own arguments
55
+ (positional stay positional, keyword stay keyword) plus a trailing ``circuit``
56
+ keyword argument carrying a ``CircuitInfo``. Its return value becomes the call's
57
+ result. If ``None``, an open circuit raises ``CircuitBreakerOpenError``.
58
+ on_transition : Callable | None
59
+ Called with a single ``CircuitTransition`` argument whenever the circuit changes
60
+ state (open, probe, close, reopen). Fires only on transitions, never on the
61
+ per-invocation hot path, so it is a safe place to emit a CloudWatch metric. Any
62
+ exception it raises is swallowed and logged so observability never breaks the
63
+ protected call.
64
+ config : CircuitBreakerConfig | None
65
+ Tunables. Defaults to ``CircuitBreakerConfig()`` when omitted.
66
+
67
+ Returns
68
+ -------
69
+ Callable
70
+ The decorated function.
71
+
72
+ Example
73
+ -------
74
+ **Protect a payment backend, buffering rejected requests**
75
+
76
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha import circuit_breaker, CircuitInfo
77
+ from aws_lambda_powertools.utilities.circuit_breaker_alpha.persistence import (
78
+ CircuitBreakerDynamoDBPersistence,
79
+ )
80
+
81
+ persistence = CircuitBreakerDynamoDBPersistence(table_name="CircuitBreakerState")
82
+
83
+ def buffer(order: dict, circuit: CircuitInfo):
84
+ sqs.send_message(QueueUrl=url, MessageBody=json.dumps(order))
85
+
86
+ @circuit_breaker(name="payment-backend", persistence_store=persistence, on_circuit_open=buffer)
87
+ def charge(order: dict) -> dict:
88
+ return payment_api.charge(order)
89
+ """
90
+ config = config or CircuitBreakerConfig()
91
+
92
+ def decorator(function: Callable) -> Callable:
93
+ @functools.wraps(function)
94
+ def wrapper(*args, **kwargs) -> Any:
95
+ # Skip the circuit entirely when disabled (development only).
96
+ if strtobool(os.getenv(constants.CIRCUIT_BREAKER_DISABLED_ENV, "false")):
97
+ warnings.warn(
98
+ message="Disabling the circuit breaker is intended for development environments only "
99
+ "and should not be used in production.",
100
+ category=PowertoolsUserWarning,
101
+ stacklevel=2,
102
+ )
103
+ return function(*args, **kwargs)
104
+
105
+ handler = CircuitBreakerHandler(
106
+ function=function,
107
+ name=name,
108
+ config=config,
109
+ persistence_store=persistence_store,
110
+ on_circuit_open=on_circuit_open,
111
+ on_transition=on_transition,
112
+ function_args=args,
113
+ function_kwargs=kwargs,
114
+ )
115
+ return handler.handle()
116
+
117
+ return wrapper
118
+
119
+ return decorator