localstack-core 4.6.1.dev60__py3-none-any.whl → 4.10.1.dev12__py3-none-any.whl

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 (672) hide show
  1. localstack/aws/api/apigateway/__init__.py +87 -110
  2. localstack/aws/api/cloudformation/__init__.py +18 -4
  3. localstack/aws/api/cloudwatch/__init__.py +41 -1
  4. localstack/aws/api/config/__init__.py +4 -0
  5. localstack/aws/api/core.py +8 -5
  6. localstack/aws/api/dynamodb/__init__.py +30 -0
  7. localstack/aws/api/ec2/__init__.py +1545 -66
  8. localstack/aws/api/events/__init__.py +12 -16
  9. localstack/aws/api/iam/__init__.py +7 -0
  10. localstack/aws/api/kinesis/__init__.py +19 -0
  11. localstack/aws/api/kms/__init__.py +6 -0
  12. localstack/aws/api/lambda_/__init__.py +36 -23
  13. localstack/aws/api/logs/__init__.py +20 -8
  14. localstack/aws/api/opensearch/__init__.py +16 -0
  15. localstack/aws/api/pipes/__init__.py +24 -32
  16. localstack/aws/api/redshift/__init__.py +9 -3
  17. localstack/aws/api/route53/__init__.py +5 -0
  18. localstack/aws/api/s3/__init__.py +12 -0
  19. localstack/aws/api/s3control/__init__.py +56 -0
  20. localstack/aws/api/scheduler/__init__.py +14 -16
  21. localstack/aws/api/ssm/__init__.py +2 -0
  22. localstack/aws/api/stepfunctions/__init__.py +88 -114
  23. localstack/aws/api/support/__init__.py +8 -9
  24. localstack/aws/api/transcribe/__init__.py +17 -0
  25. localstack/aws/chain.py +2 -2
  26. localstack/aws/client.py +14 -11
  27. localstack/aws/connect.py +42 -41
  28. localstack/aws/forwarder.py +57 -9
  29. localstack/aws/gateway.py +1 -3
  30. localstack/aws/handlers/analytics.py +2 -3
  31. localstack/aws/handlers/cors.py +4 -5
  32. localstack/aws/handlers/internal_requests.py +6 -1
  33. localstack/aws/handlers/logging.py +13 -4
  34. localstack/aws/handlers/metric_handler.py +44 -5
  35. localstack/aws/handlers/service.py +48 -28
  36. localstack/aws/mocking.py +18 -27
  37. localstack/aws/patches.py +2 -2
  38. localstack/aws/protocol/op_router.py +11 -10
  39. localstack/aws/protocol/parser.py +475 -49
  40. localstack/aws/protocol/serializer.py +723 -106
  41. localstack/aws/protocol/service_router.py +133 -33
  42. localstack/aws/protocol/validate.py +6 -6
  43. localstack/aws/scaffold.py +9 -10
  44. localstack/aws/serving/edge.py +5 -6
  45. localstack/aws/serving/hypercorn.py +2 -2
  46. localstack/aws/serving/twisted.py +1 -2
  47. localstack/aws/serving/werkzeug.py +2 -2
  48. localstack/aws/skeleton.py +12 -11
  49. localstack/aws/spec-patches.json +58 -0
  50. localstack/aws/spec.py +66 -46
  51. localstack/cli/exceptions.py +1 -1
  52. localstack/cli/localstack.py +11 -11
  53. localstack/cli/lpm.py +4 -5
  54. localstack/cli/plugins.py +1 -1
  55. localstack/cli/profiles.py +1 -2
  56. localstack/config.py +44 -30
  57. localstack/constants.py +4 -29
  58. localstack/deprecations.py +5 -5
  59. localstack/dev/kubernetes/__main__.py +130 -7
  60. localstack/dev/run/__main__.py +5 -5
  61. localstack/dev/run/configurators.py +1 -4
  62. localstack/dev/run/paths.py +6 -6
  63. localstack/dns/models.py +2 -1
  64. localstack/dns/plugins.py +5 -1
  65. localstack/dns/server.py +16 -6
  66. localstack/http/dispatcher.py +1 -2
  67. localstack/http/response.py +2 -2
  68. localstack/http/router.py +1 -1
  69. localstack/http/trace.py +2 -1
  70. localstack/logging/format.py +6 -6
  71. localstack/packages/api.py +13 -12
  72. localstack/packages/core.py +4 -4
  73. localstack/packages/debugpy.py +1 -3
  74. localstack/packages/ffmpeg.py +1 -2
  75. localstack/packages/java.py +38 -12
  76. localstack/packages/plugins.py +0 -8
  77. localstack/runtime/analytics.py +3 -0
  78. localstack/runtime/hooks.py +1 -1
  79. localstack/runtime/init.py +8 -9
  80. localstack/runtime/main.py +5 -5
  81. localstack/runtime/patches.py +2 -2
  82. localstack/runtime/shutdown.py +2 -1
  83. localstack/services/apigateway/exporter.py +1 -2
  84. localstack/services/apigateway/helpers.py +7 -10
  85. localstack/services/apigateway/legacy/context.py +21 -21
  86. localstack/services/apigateway/legacy/helpers.py +27 -28
  87. localstack/services/apigateway/legacy/integration.py +11 -10
  88. localstack/services/apigateway/legacy/invocations.py +6 -5
  89. localstack/services/apigateway/legacy/provider.py +148 -68
  90. localstack/services/apigateway/legacy/router_asf.py +2 -2
  91. localstack/services/apigateway/legacy/templates.py +6 -6
  92. localstack/services/apigateway/models.py +16 -16
  93. localstack/services/apigateway/next_gen/execute_api/api.py +2 -2
  94. localstack/services/apigateway/next_gen/execute_api/context.py +25 -25
  95. localstack/services/apigateway/next_gen/execute_api/handlers/api_key_validation.py +2 -5
  96. localstack/services/apigateway/next_gen/execute_api/handlers/method_request.py +7 -2
  97. localstack/services/apigateway/next_gen/execute_api/handlers/parse.py +1 -2
  98. localstack/services/apigateway/next_gen/execute_api/handlers/resource_router.py +2 -3
  99. localstack/services/apigateway/next_gen/execute_api/header_utils.py +1 -1
  100. localstack/services/apigateway/next_gen/execute_api/helpers.py +2 -2
  101. localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +9 -6
  102. localstack/services/apigateway/next_gen/execute_api/integrations/http.py +12 -12
  103. localstack/services/apigateway/next_gen/execute_api/router.py +31 -0
  104. localstack/services/apigateway/next_gen/execute_api/template_mapping.py +2 -2
  105. localstack/services/apigateway/next_gen/execute_api/test_invoke.py +114 -9
  106. localstack/services/apigateway/next_gen/execute_api/variables.py +63 -63
  107. localstack/services/apigateway/next_gen/provider.py +5 -0
  108. localstack/services/apigateway/resource_providers/aws_apigateway_account.py +3 -3
  109. localstack/services/apigateway/resource_providers/aws_apigateway_account_plugin.py +1 -3
  110. localstack/services/apigateway/resource_providers/aws_apigateway_apikey.py +14 -14
  111. localstack/services/apigateway/resource_providers/aws_apigateway_apikey_plugin.py +1 -3
  112. localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py +5 -5
  113. localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping_plugin.py +1 -3
  114. localstack/services/apigateway/resource_providers/aws_apigateway_deployment.py +46 -46
  115. localstack/services/apigateway/resource_providers/aws_apigateway_deployment_plugin.py +1 -3
  116. localstack/services/apigateway/resource_providers/aws_apigateway_domainname.py +18 -18
  117. localstack/services/apigateway/resource_providers/aws_apigateway_domainname_plugin.py +1 -3
  118. localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse.py +7 -7
  119. localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse_plugin.py +1 -3
  120. localstack/services/apigateway/resource_providers/aws_apigateway_method.py +36 -36
  121. localstack/services/apigateway/resource_providers/aws_apigateway_method_plugin.py +1 -3
  122. localstack/services/apigateway/resource_providers/aws_apigateway_model.py +6 -6
  123. localstack/services/apigateway/resource_providers/aws_apigateway_model_plugin.py +1 -3
  124. localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator.py +6 -6
  125. localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator_plugin.py +1 -3
  126. localstack/services/apigateway/resource_providers/aws_apigateway_resource.py +6 -6
  127. localstack/services/apigateway/resource_providers/aws_apigateway_resource_plugin.py +1 -3
  128. localstack/services/apigateway/resource_providers/aws_apigateway_restapi.py +26 -26
  129. localstack/services/apigateway/resource_providers/aws_apigateway_restapi_plugin.py +1 -3
  130. localstack/services/apigateway/resource_providers/aws_apigateway_stage.py +33 -33
  131. localstack/services/apigateway/resource_providers/aws_apigateway_stage_plugin.py +1 -3
  132. localstack/services/apigateway/resource_providers/aws_apigateway_usageplan.py +18 -18
  133. localstack/services/apigateway/resource_providers/aws_apigateway_usageplan_plugin.py +1 -3
  134. localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey.py +5 -5
  135. localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey_plugin.py +1 -3
  136. localstack/services/cdk/resource_providers/cdk_metadata.py +4 -3
  137. localstack/services/cdk/resource_providers/cdk_metadata_plugin.py +1 -3
  138. localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate.py +14 -14
  139. localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate_plugin.py +1 -3
  140. localstack/services/cloudformation/api_utils.py +4 -8
  141. localstack/services/cloudformation/cfn_utils.py +2 -2
  142. localstack/services/cloudformation/deployment_utils.py +14 -12
  143. localstack/services/cloudformation/engine/changes.py +3 -3
  144. localstack/services/cloudformation/engine/entities.py +27 -17
  145. localstack/services/cloudformation/engine/parameters.py +4 -4
  146. localstack/services/cloudformation/engine/template_deployer.py +15 -14
  147. localstack/services/cloudformation/engine/template_utils.py +34 -12
  148. localstack/services/cloudformation/engine/transformers.py +11 -8
  149. localstack/services/cloudformation/engine/types.py +5 -4
  150. localstack/services/cloudformation/engine/v2/change_set_model.py +336 -39
  151. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +96 -17
  152. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +289 -136
  153. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +315 -146
  154. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +380 -105
  155. localstack/services/cloudformation/engine/v2/change_set_model_validator.py +183 -0
  156. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +6 -0
  157. localstack/services/cloudformation/engine/v2/resolving.py +102 -0
  158. localstack/services/cloudformation/engine/yaml_parser.py +9 -2
  159. localstack/services/cloudformation/provider.py +11 -6
  160. localstack/services/cloudformation/provider_utils.py +34 -4
  161. localstack/services/cloudformation/resource_provider.py +31 -21
  162. localstack/services/cloudformation/resource_providers/aws_cloudformation_macro.py +7 -7
  163. localstack/services/cloudformation/resource_providers/aws_cloudformation_macro_plugin.py +1 -3
  164. localstack/services/cloudformation/resource_providers/aws_cloudformation_stack.py +9 -9
  165. localstack/services/cloudformation/resource_providers/aws_cloudformation_stack_plugin.py +1 -3
  166. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition.py +6 -6
  167. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition_plugin.py +1 -3
  168. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle.py +2 -2
  169. localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle_plugin.py +1 -3
  170. localstack/services/cloudformation/resources.py +24149 -0
  171. localstack/services/cloudformation/scaffolding/__main__.py +13 -12
  172. localstack/services/cloudformation/scaffolding/propgen.py +2 -2
  173. localstack/services/cloudformation/service_models.py +2 -2
  174. localstack/services/cloudformation/stores.py +33 -22
  175. localstack/services/cloudformation/v2/entities.py +103 -88
  176. localstack/services/cloudformation/v2/provider.py +872 -131
  177. localstack/services/cloudformation/v2/types.py +38 -0
  178. localstack/services/cloudformation/v2/utils.py +4 -1
  179. localstack/services/cloudwatch/alarm_scheduler.py +11 -8
  180. localstack/services/cloudwatch/cloudwatch_database_helper.py +4 -5
  181. localstack/services/cloudwatch/models.py +5 -7
  182. localstack/services/cloudwatch/provider.py +30 -25
  183. localstack/services/cloudwatch/provider_v2.py +27 -32
  184. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm.py +40 -40
  185. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm_plugin.py +1 -3
  186. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm.py +12 -12
  187. localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm_plugin.py +1 -3
  188. localstack/services/dynamodb/packages.py +3 -3
  189. localstack/services/dynamodb/provider.py +159 -18
  190. localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable.py +63 -63
  191. localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable_plugin.py +1 -3
  192. localstack/services/dynamodb/resource_providers/aws_dynamodb_table.py +57 -57
  193. localstack/services/dynamodb/resource_providers/aws_dynamodb_table_plugin.py +1 -3
  194. localstack/services/dynamodb/server.py +2 -2
  195. localstack/services/dynamodb/utils.py +13 -14
  196. localstack/services/dynamodb/v2/provider.py +157 -18
  197. localstack/services/dynamodbstreams/dynamodbstreams_api.py +2 -2
  198. localstack/services/dynamodbstreams/models.py +1 -3
  199. localstack/services/ec2/patches.py +26 -5
  200. localstack/services/ec2/provider.py +3 -3
  201. localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions.py +10 -10
  202. localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions_plugin.py +1 -3
  203. localstack/services/ec2/resource_providers/aws_ec2_instance.py +96 -96
  204. localstack/services/ec2/resource_providers/aws_ec2_instance_plugin.py +1 -3
  205. localstack/services/ec2/resource_providers/aws_ec2_internetgateway.py +5 -5
  206. localstack/services/ec2/resource_providers/aws_ec2_internetgateway_plugin.py +1 -3
  207. localstack/services/ec2/resource_providers/aws_ec2_keypair.py +10 -10
  208. localstack/services/ec2/resource_providers/aws_ec2_keypair_plugin.py +1 -3
  209. localstack/services/ec2/resource_providers/aws_ec2_natgateway.py +13 -13
  210. localstack/services/ec2/resource_providers/aws_ec2_natgateway_plugin.py +1 -3
  211. localstack/services/ec2/resource_providers/aws_ec2_networkacl.py +6 -6
  212. localstack/services/ec2/resource_providers/aws_ec2_networkacl_plugin.py +1 -3
  213. localstack/services/ec2/resource_providers/aws_ec2_prefixlist.py +14 -14
  214. localstack/services/ec2/resource_providers/aws_ec2_prefixlist_plugin.py +1 -3
  215. localstack/services/ec2/resource_providers/aws_ec2_route.py +15 -15
  216. localstack/services/ec2/resource_providers/aws_ec2_route_plugin.py +1 -3
  217. localstack/services/ec2/resource_providers/aws_ec2_routetable.py +6 -6
  218. localstack/services/ec2/resource_providers/aws_ec2_routetable_plugin.py +1 -3
  219. localstack/services/ec2/resource_providers/aws_ec2_securitygroup.py +29 -29
  220. localstack/services/ec2/resource_providers/aws_ec2_securitygroup_plugin.py +1 -3
  221. localstack/services/ec2/resource_providers/aws_ec2_subnet.py +19 -19
  222. localstack/services/ec2/resource_providers/aws_ec2_subnet_plugin.py +1 -3
  223. localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation.py +4 -4
  224. localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation_plugin.py +1 -3
  225. localstack/services/ec2/resource_providers/aws_ec2_transitgateway.py +16 -16
  226. localstack/services/ec2/resource_providers/aws_ec2_transitgateway_plugin.py +1 -3
  227. localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment.py +9 -9
  228. localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment_plugin.py +1 -3
  229. localstack/services/ec2/resource_providers/aws_ec2_vpc.py +15 -15
  230. localstack/services/ec2/resource_providers/aws_ec2_vpc_plugin.py +1 -3
  231. localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint.py +29 -22
  232. localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint_plugin.py +1 -3
  233. localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment.py +5 -5
  234. localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment_plugin.py +1 -3
  235. localstack/services/ecr/resource_providers/aws_ecr_repository.py +22 -19
  236. localstack/services/ecr/resource_providers/aws_ecr_repository_plugin.py +1 -3
  237. localstack/services/edge.py +6 -6
  238. localstack/services/es/provider.py +21 -21
  239. localstack/services/events/archive.py +2 -2
  240. localstack/services/events/connection.py +5 -5
  241. localstack/services/events/event_bus.py +9 -9
  242. localstack/services/events/event_rule_engine.py +31 -13
  243. localstack/services/events/models.py +29 -30
  244. localstack/services/events/provider.py +29 -26
  245. localstack/services/events/replay.py +3 -3
  246. localstack/services/events/resource_providers/aws_events_apidestination.py +8 -8
  247. localstack/services/events/resource_providers/aws_events_apidestination_plugin.py +1 -3
  248. localstack/services/events/resource_providers/aws_events_connection.py +27 -27
  249. localstack/services/events/resource_providers/aws_events_connection_plugin.py +1 -3
  250. localstack/services/events/resource_providers/aws_events_eventbus.py +9 -9
  251. localstack/services/events/resource_providers/aws_events_eventbus_plugin.py +1 -3
  252. localstack/services/events/resource_providers/aws_events_eventbuspolicy.py +11 -11
  253. localstack/services/events/resource_providers/aws_events_eventbuspolicy_plugin.py +1 -3
  254. localstack/services/events/resource_providers/aws_events_rule.py +82 -82
  255. localstack/services/events/resource_providers/aws_events_rule_plugin.py +1 -3
  256. localstack/services/events/rule.py +15 -15
  257. localstack/services/events/target.py +21 -13
  258. localstack/services/events/utils.py +7 -7
  259. localstack/services/events/v1/models.py +1 -3
  260. localstack/services/events/v1/provider.py +15 -15
  261. localstack/services/firehose/models.py +1 -3
  262. localstack/services/firehose/provider.py +25 -16
  263. localstack/services/iam/iam_patches.py +5 -6
  264. localstack/services/iam/provider.py +14 -119
  265. localstack/services/iam/resource_providers/aws_iam_accesskey.py +6 -6
  266. localstack/services/iam/resource_providers/aws_iam_accesskey_plugin.py +1 -3
  267. localstack/services/iam/resource_providers/aws_iam_group.py +9 -9
  268. localstack/services/iam/resource_providers/aws_iam_group_plugin.py +1 -3
  269. localstack/services/iam/resource_providers/aws_iam_instanceprofile.py +5 -5
  270. localstack/services/iam/resource_providers/aws_iam_instanceprofile_plugin.py +1 -3
  271. localstack/services/iam/resource_providers/aws_iam_managedpolicy.py +9 -9
  272. localstack/services/iam/resource_providers/aws_iam_managedpolicy_plugin.py +1 -3
  273. localstack/services/iam/resource_providers/aws_iam_policy.py +7 -7
  274. localstack/services/iam/resource_providers/aws_iam_policy_plugin.py +1 -3
  275. localstack/services/iam/resource_providers/aws_iam_role.py +16 -16
  276. localstack/services/iam/resource_providers/aws_iam_role_plugin.py +1 -3
  277. localstack/services/iam/resource_providers/aws_iam_servercertificate.py +10 -10
  278. localstack/services/iam/resource_providers/aws_iam_servercertificate_plugin.py +1 -3
  279. localstack/services/iam/resource_providers/aws_iam_servicelinkedrole.py +5 -5
  280. localstack/services/iam/resource_providers/aws_iam_servicelinkedrole_plugin.py +1 -3
  281. localstack/services/iam/resource_providers/aws_iam_user.py +17 -17
  282. localstack/services/iam/resource_providers/aws_iam_user_plugin.py +1 -3
  283. localstack/services/iam/resources/policy_simulator.py +133 -0
  284. localstack/services/kinesis/kinesis_mock_server.py +7 -8
  285. localstack/services/kinesis/models.py +17 -5
  286. localstack/services/kinesis/packages.py +3 -3
  287. localstack/services/kinesis/provider.py +86 -3
  288. localstack/services/kinesis/resource_providers/aws_kinesis_stream.py +13 -13
  289. localstack/services/kinesis/resource_providers/aws_kinesis_stream_plugin.py +1 -3
  290. localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer.py +7 -7
  291. localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer_plugin.py +1 -3
  292. localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream.py +191 -191
  293. localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream_plugin.py +1 -3
  294. localstack/services/kms/models.py +21 -18
  295. localstack/services/kms/provider.py +62 -26
  296. localstack/services/kms/resource_providers/aws_kms_alias.py +3 -3
  297. localstack/services/kms/resource_providers/aws_kms_alias_plugin.py +1 -3
  298. localstack/services/kms/resource_providers/aws_kms_key.py +14 -14
  299. localstack/services/kms/resource_providers/aws_kms_key_plugin.py +1 -3
  300. localstack/services/kms/utils.py +4 -3
  301. localstack/services/lambda_/api_utils.py +19 -16
  302. localstack/services/lambda_/custom_endpoints.py +2 -2
  303. localstack/services/lambda_/event_source_mapping/esm_worker_factory.py +4 -7
  304. localstack/services/lambda_/event_source_mapping/pipe_utils.py +2 -2
  305. localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +1 -1
  306. localstack/services/lambda_/event_source_mapping/senders/sender_utils.py +2 -1
  307. localstack/services/lambda_/hooks.py +6 -1
  308. localstack/services/lambda_/invocation/assignment.py +1 -2
  309. localstack/services/lambda_/invocation/docker_runtime_executor.py +7 -11
  310. localstack/services/lambda_/invocation/event_manager.py +1 -1
  311. localstack/services/lambda_/invocation/execution_environment.py +4 -4
  312. localstack/services/lambda_/invocation/executor_endpoint.py +8 -11
  313. localstack/services/lambda_/invocation/internal_sqs_queue.py +6 -10
  314. localstack/services/lambda_/invocation/lambda_models.py +33 -30
  315. localstack/services/lambda_/invocation/lambda_service.py +12 -5
  316. localstack/services/lambda_/invocation/logs.py +2 -3
  317. localstack/services/lambda_/invocation/runtime_executor.py +3 -3
  318. localstack/services/lambda_/invocation/version_manager.py +31 -8
  319. localstack/services/lambda_/ldm.py +14 -0
  320. localstack/services/lambda_/packages.py +3 -4
  321. localstack/services/lambda_/provider.py +9 -26
  322. localstack/services/lambda_/provider_utils.py +1 -1
  323. localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig.py +8 -8
  324. localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig_plugin.py +1 -3
  325. localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig.py +11 -11
  326. localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig_plugin.py +1 -3
  327. localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping.py +39 -39
  328. localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping_plugin.py +1 -3
  329. localstack/services/lambda_/resource_providers/aws_lambda_function.py +54 -54
  330. localstack/services/lambda_/resource_providers/aws_lambda_function_plugin.py +1 -3
  331. localstack/services/lambda_/resource_providers/aws_lambda_layerversion.py +11 -11
  332. localstack/services/lambda_/resource_providers/aws_lambda_layerversion_plugin.py +1 -3
  333. localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission.py +6 -6
  334. localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission_plugin.py +1 -3
  335. localstack/services/lambda_/resource_providers/aws_lambda_permission.py +10 -10
  336. localstack/services/lambda_/resource_providers/aws_lambda_permission_plugin.py +1 -3
  337. localstack/services/lambda_/resource_providers/aws_lambda_url.py +15 -15
  338. localstack/services/lambda_/resource_providers/aws_lambda_url_plugin.py +1 -3
  339. localstack/services/lambda_/resource_providers/aws_lambda_version.py +8 -8
  340. localstack/services/lambda_/resource_providers/aws_lambda_version_plugin.py +1 -3
  341. localstack/services/lambda_/resource_providers/lambda_alias.py +12 -12
  342. localstack/services/lambda_/resource_providers/lambda_alias_plugin.py +1 -3
  343. localstack/services/lambda_/runtimes.py +1 -3
  344. localstack/services/lambda_/urlrouter.py +14 -1
  345. localstack/services/logs/models.py +1 -3
  346. localstack/services/logs/provider.py +39 -22
  347. localstack/services/logs/resource_providers/aws_logs_loggroup.py +9 -9
  348. localstack/services/logs/resource_providers/aws_logs_loggroup_plugin.py +1 -3
  349. localstack/services/logs/resource_providers/aws_logs_logstream.py +4 -4
  350. localstack/services/logs/resource_providers/aws_logs_logstream_plugin.py +1 -3
  351. localstack/services/logs/resource_providers/aws_logs_subscriptionfilter.py +7 -7
  352. localstack/services/logs/resource_providers/aws_logs_subscriptionfilter_plugin.py +1 -3
  353. localstack/services/moto.py +5 -4
  354. localstack/services/opensearch/cluster.py +28 -20
  355. localstack/services/opensearch/cluster_manager.py +13 -14
  356. localstack/services/opensearch/models.py +1 -3
  357. localstack/services/opensearch/packages.py +27 -9
  358. localstack/services/opensearch/provider.py +15 -10
  359. localstack/services/opensearch/resource_providers/aws_elasticsearch_domain.py +61 -61
  360. localstack/services/opensearch/resource_providers/aws_elasticsearch_domain_plugin.py +1 -3
  361. localstack/services/opensearch/resource_providers/aws_opensearchservice_domain.py +89 -89
  362. localstack/services/opensearch/resource_providers/aws_opensearchservice_domain_plugin.py +1 -3
  363. localstack/services/opensearch/versions.py +57 -10
  364. localstack/services/plugins.py +37 -32
  365. localstack/services/providers.py +10 -2
  366. localstack/services/redshift/provider.py +0 -21
  367. localstack/services/redshift/resource_providers/aws_redshift_cluster.py +57 -57
  368. localstack/services/redshift/resource_providers/aws_redshift_cluster_plugin.py +1 -3
  369. localstack/services/resource_groups/resource_providers/aws_resourcegroups_group.py +21 -21
  370. localstack/services/resource_groups/resource_providers/aws_resourcegroups_group_plugin.py +1 -3
  371. localstack/services/route53/models.py +1 -3
  372. localstack/services/route53/provider.py +1 -2
  373. localstack/services/route53/resource_providers/aws_route53_healthcheck.py +6 -6
  374. localstack/services/route53/resource_providers/aws_route53_healthcheck_plugin.py +1 -3
  375. localstack/services/route53/resource_providers/aws_route53_recordset.py +27 -27
  376. localstack/services/route53/resource_providers/aws_route53_recordset_plugin.py +1 -3
  377. localstack/services/route53resolver/models.py +8 -10
  378. localstack/services/route53resolver/provider.py +12 -12
  379. localstack/services/s3/codec.py +2 -2
  380. localstack/services/s3/constants.py +5 -2
  381. localstack/services/s3/cors.py +8 -8
  382. localstack/services/s3/models.py +73 -73
  383. localstack/services/s3/notifications.py +74 -58
  384. localstack/services/s3/presigned_url.py +41 -59
  385. localstack/services/s3/provider.py +86 -29
  386. localstack/services/s3/resource_providers/aws_s3_bucket.py +180 -180
  387. localstack/services/s3/resource_providers/aws_s3_bucket_plugin.py +1 -3
  388. localstack/services/s3/resource_providers/aws_s3_bucketpolicy.py +4 -4
  389. localstack/services/s3/resource_providers/aws_s3_bucketpolicy_plugin.py +1 -3
  390. localstack/services/s3/storage/core.py +4 -3
  391. localstack/services/s3/storage/ephemeral.py +7 -6
  392. localstack/services/s3/utils.py +51 -31
  393. localstack/services/s3/validation.py +47 -33
  394. localstack/services/s3/website_hosting.py +9 -7
  395. localstack/services/scheduler/resource_providers/aws_scheduler_schedule.py +60 -60
  396. localstack/services/scheduler/resource_providers/aws_scheduler_schedule_plugin.py +1 -3
  397. localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup.py +9 -9
  398. localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup_plugin.py +1 -3
  399. localstack/services/secretsmanager/provider.py +10 -12
  400. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy.py +5 -5
  401. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy_plugin.py +1 -3
  402. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule.py +21 -21
  403. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule_plugin.py +1 -3
  404. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret.py +23 -23
  405. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret_plugin.py +1 -3
  406. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment.py +5 -5
  407. localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment_plugin.py +1 -3
  408. localstack/services/ses/models.py +8 -1
  409. localstack/services/ses/provider.py +128 -55
  410. localstack/services/ses/resource_providers/aws_ses_emailidentity.py +21 -21
  411. localstack/services/ses/resource_providers/aws_ses_emailidentity_plugin.py +1 -3
  412. localstack/services/sns/constants.py +7 -1
  413. localstack/services/sns/executor.py +9 -2
  414. localstack/services/sns/models.py +25 -25
  415. localstack/services/sns/provider.py +9 -7
  416. localstack/services/sns/publisher.py +37 -23
  417. localstack/services/sns/resource_providers/aws_sns_subscription.py +13 -13
  418. localstack/services/sns/resource_providers/aws_sns_subscription_plugin.py +1 -3
  419. localstack/services/sns/resource_providers/aws_sns_topic.py +16 -16
  420. localstack/services/sns/resource_providers/aws_sns_topic_plugin.py +1 -3
  421. localstack/services/sns/resource_providers/aws_sns_topicpolicy.py +4 -4
  422. localstack/services/sns/resource_providers/aws_sns_topicpolicy_plugin.py +1 -3
  423. localstack/services/sns/v2/models.py +167 -0
  424. localstack/services/sns/v2/provider.py +867 -0
  425. localstack/services/sns/v2/utils.py +130 -0
  426. localstack/services/sqs/constants.py +2 -2
  427. localstack/services/sqs/developer_api.py +205 -0
  428. localstack/services/sqs/models.py +71 -36
  429. localstack/services/sqs/provider.py +56 -332
  430. localstack/services/sqs/query_api.py +8 -5
  431. localstack/services/sqs/resource_providers/aws_sqs_queue.py +21 -21
  432. localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py +1 -3
  433. localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py +7 -5
  434. localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py +1 -3
  435. localstack/services/sqs/utils.py +123 -4
  436. localstack/services/ssm/provider.py +3 -4
  437. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow.py +15 -15
  438. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow_plugin.py +1 -3
  439. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget.py +10 -10
  440. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget_plugin.py +1 -3
  441. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask.py +48 -48
  442. localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask_plugin.py +1 -3
  443. localstack/services/ssm/resource_providers/aws_ssm_parameter.py +10 -10
  444. localstack/services/ssm/resource_providers/aws_ssm_parameter_plugin.py +1 -3
  445. localstack/services/ssm/resource_providers/aws_ssm_patchbaseline.py +29 -29
  446. localstack/services/ssm/resource_providers/aws_ssm_patchbaseline_plugin.py +1 -3
  447. localstack/services/stepfunctions/asl/antlt4utils/antlr4utils.py +3 -4
  448. localstack/services/stepfunctions/asl/component/common/assign/assign_decl.py +1 -1
  449. localstack/services/stepfunctions/asl/component/common/assign/assign_decl_binding.py +1 -1
  450. localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_array.py +1 -1
  451. localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_object.py +1 -1
  452. localstack/services/stepfunctions/asl/component/common/catch/catcher_decl.py +9 -9
  453. localstack/services/stepfunctions/asl/component/common/error_name/custom_error_name.py +2 -2
  454. localstack/services/stepfunctions/asl/component/common/error_name/error_name.py +4 -4
  455. localstack/services/stepfunctions/asl/component/common/error_name/failure_event.py +8 -8
  456. localstack/services/stepfunctions/asl/component/common/error_name/states_error_name_type.py +1 -1
  457. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_binding.py +2 -2
  458. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_array.py +1 -1
  459. localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_object.py +1 -1
  460. localstack/services/stepfunctions/asl/component/common/path/input_path.py +4 -4
  461. localstack/services/stepfunctions/asl/component/common/path/output_path.py +4 -4
  462. localstack/services/stepfunctions/asl/component/common/path/result_path.py +3 -3
  463. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py +1 -1
  464. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py +3 -3
  465. localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py +1 -1
  466. localstack/services/stepfunctions/asl/component/common/retry/retrier_decl.py +8 -8
  467. localstack/services/stepfunctions/asl/component/common/string/string_expression.py +3 -3
  468. localstack/services/stepfunctions/asl/component/common/timeouts/timeout.py +3 -3
  469. localstack/services/stepfunctions/asl/component/eval_component.py +2 -3
  470. localstack/services/stepfunctions/asl/component/intrinsic/argument/argument.py +4 -4
  471. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/array/array_partition.py +1 -1
  472. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/generic/string_format.py +1 -1
  473. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_array.py +1 -1
  474. localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_format.py +1 -1
  475. localstack/services/stepfunctions/asl/component/intrinsic/jsonata.py +3 -3
  476. localstack/services/stepfunctions/asl/component/intrinsic/member.py +1 -1
  477. localstack/services/stepfunctions/asl/component/program/program.py +9 -9
  478. localstack/services/stepfunctions/asl/component/program/states.py +1 -1
  479. localstack/services/stepfunctions/asl/component/state/state.py +10 -11
  480. localstack/services/stepfunctions/asl/component/state/state_choice/choice_rule.py +11 -11
  481. localstack/services/stepfunctions/asl/component/state/state_choice/comparison/comparison.py +5 -11
  482. localstack/services/stepfunctions/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py +2 -2
  483. localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +3 -5
  484. localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +9 -9
  485. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py +7 -7
  486. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py +5 -5
  487. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py +2 -1
  488. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py +2 -2
  489. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py +8 -8
  490. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py +7 -7
  491. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py +4 -4
  492. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py +5 -5
  493. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py +10 -10
  494. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_component.py +3 -3
  495. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py +3 -3
  496. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_worker.py +2 -2
  497. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/distributed_iterator_worker.py +3 -5
  498. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator.py +1 -2
  499. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator_worker.py +5 -5
  500. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/job.py +9 -9
  501. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/result_writer/resource_eval/resource_eval_s3.py +2 -1
  502. localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +12 -13
  503. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branch_worker.py +3 -3
  504. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branches_decl.py +7 -7
  505. localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/state_parallel.py +2 -3
  506. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +7 -7
  507. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/resource.py +3 -3
  508. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +10 -10
  509. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py +18 -18
  510. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py +1 -1
  511. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_batch.py +8 -7
  512. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +18 -17
  513. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py +2 -2
  514. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_ecs.py +5 -4
  515. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_events.py +4 -4
  516. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_glue.py +7 -6
  517. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py +4 -4
  518. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py +9 -8
  519. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sns.py +2 -2
  520. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py +4 -4
  521. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task.py +5 -5
  522. localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py +2 -2
  523. localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +3 -5
  524. localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +5 -7
  525. localstack/services/stepfunctions/asl/component/state/state_succeed/state_succeed.py +1 -1
  526. localstack/services/stepfunctions/asl/component/state/state_wait/state_wait.py +1 -1
  527. localstack/services/stepfunctions/asl/component/state/state_wait/wait_function/timestamp.py +2 -2
  528. localstack/services/stepfunctions/asl/eval/callback/callback.py +18 -18
  529. localstack/services/stepfunctions/asl/eval/environment.py +22 -24
  530. localstack/services/stepfunctions/asl/eval/evaluation_details.py +3 -5
  531. localstack/services/stepfunctions/asl/eval/event/event_manager.py +10 -10
  532. localstack/services/stepfunctions/asl/eval/event/logging.py +3 -3
  533. localstack/services/stepfunctions/asl/eval/program_state.py +8 -8
  534. localstack/services/stepfunctions/asl/eval/states.py +12 -12
  535. localstack/services/stepfunctions/asl/eval/test_state/environment.py +3 -5
  536. localstack/services/stepfunctions/asl/eval/variable_store.py +6 -6
  537. localstack/services/stepfunctions/asl/jsonata/jsonata.py +7 -6
  538. localstack/services/stepfunctions/asl/parse/asl_parser.py +1 -1
  539. localstack/services/stepfunctions/asl/parse/intrinsic/preprocessor.py +2 -3
  540. localstack/services/stepfunctions/asl/parse/preprocessor.py +44 -44
  541. localstack/services/stepfunctions/asl/parse/typed_props.py +2 -2
  542. localstack/services/stepfunctions/asl/static_analyser/intrinsic/variable_names_intrinsic_static_analyser.py +1 -1
  543. localstack/services/stepfunctions/asl/static_analyser/variable_references_static_analyser.py +2 -2
  544. localstack/services/stepfunctions/asl/utils/encoding.py +2 -2
  545. localstack/services/stepfunctions/asl/utils/json_path.py +2 -2
  546. localstack/services/stepfunctions/backend/activity.py +4 -4
  547. localstack/services/stepfunctions/backend/alias.py +8 -8
  548. localstack/services/stepfunctions/backend/execution.py +29 -30
  549. localstack/services/stepfunctions/backend/execution_worker.py +7 -7
  550. localstack/services/stepfunctions/backend/state_machine.py +28 -28
  551. localstack/services/stepfunctions/backend/test_state/execution.py +3 -4
  552. localstack/services/stepfunctions/backend/test_state/execution_worker.py +1 -3
  553. localstack/services/stepfunctions/mocking/mock_config.py +9 -9
  554. localstack/services/stepfunctions/mocking/mock_config_file.py +10 -10
  555. localstack/services/stepfunctions/packages.py +14 -5
  556. localstack/services/stepfunctions/provider.py +34 -44
  557. localstack/services/stepfunctions/quotas.py +2 -3
  558. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity.py +6 -6
  559. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity_plugin.py +1 -3
  560. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine.py +25 -25
  561. localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine_plugin.py +1 -3
  562. localstack/services/stepfunctions/stepfunctions_utils.py +1 -2
  563. localstack/services/stores.py +8 -8
  564. localstack/services/transcribe/packages.py +1 -3
  565. localstack/services/transcribe/provider.py +8 -3
  566. localstack/state/codecs.py +61 -0
  567. localstack/state/core.py +11 -5
  568. localstack/state/inspect.py +4 -4
  569. localstack/state/pickle.py +36 -23
  570. localstack/testing/aws/asf_utils.py +3 -2
  571. localstack/testing/aws/cloudformation_utils.py +1 -1
  572. localstack/testing/aws/lambda_utils.py +15 -14
  573. localstack/testing/aws/util.py +3 -2
  574. localstack/testing/pytest/cloudformation/fixtures.py +68 -18
  575. localstack/testing/pytest/container.py +5 -5
  576. localstack/testing/pytest/filters.py +1 -3
  577. localstack/testing/pytest/fixtures.py +188 -49
  578. localstack/testing/pytest/in_memory_localstack.py +1 -3
  579. localstack/testing/pytest/marking.py +42 -15
  580. localstack/testing/pytest/path_filter.py +1 -1
  581. localstack/testing/pytest/stepfunctions/fixtures.py +4 -4
  582. localstack/testing/pytest/stepfunctions/utils.py +11 -10
  583. localstack/testing/pytest/util.py +1 -1
  584. localstack/testing/pytest/validation_tracking.py +3 -4
  585. localstack/testing/scenario/provisioning.py +11 -10
  586. localstack/testing/snapshots/transformer_utility.py +8 -3
  587. localstack/testing/testselection/matching.py +2 -2
  588. localstack/testing/testselection/opt_out.py +1 -1
  589. localstack/testing/testselection/scripts/filter_by_test_selection.py +1 -1
  590. localstack/testing/testselection/scripts/generate_test_selection.py +1 -1
  591. localstack/testing/testselection/testselection.py +2 -2
  592. localstack/utils/analytics/cli.py +2 -3
  593. localstack/utils/analytics/client.py +5 -5
  594. localstack/utils/analytics/events.py +2 -2
  595. localstack/utils/analytics/metadata.py +6 -4
  596. localstack/utils/analytics/metrics/counter.py +11 -18
  597. localstack/utils/analytics/metrics/registry.py +2 -2
  598. localstack/utils/analytics/publisher.py +4 -5
  599. localstack/utils/analytics/service_providers.py +19 -0
  600. localstack/utils/analytics/service_request_aggregator.py +4 -4
  601. localstack/utils/archives.py +12 -12
  602. localstack/utils/asyncio.py +2 -2
  603. localstack/utils/aws/arns.py +26 -31
  604. localstack/utils/aws/aws_responses.py +21 -28
  605. localstack/utils/aws/aws_stack.py +7 -12
  606. localstack/utils/aws/dead_letter_queue.py +4 -9
  607. localstack/utils/aws/message_forwarding.py +8 -11
  608. localstack/utils/aws/request_context.py +5 -6
  609. localstack/utils/aws/resources.py +1 -1
  610. localstack/utils/aws/templating.py +4 -4
  611. localstack/utils/batch_policy.py +4 -4
  612. localstack/utils/bootstrap.py +37 -30
  613. localstack/utils/catalog/catalog.py +139 -0
  614. localstack/utils/catalog/catalog_loader.py +119 -0
  615. localstack/utils/catalog/common.py +58 -0
  616. localstack/utils/catalog/plugins.py +28 -0
  617. localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
  618. localstack/utils/collections.py +33 -27
  619. localstack/utils/config_listener.py +2 -2
  620. localstack/utils/container_networking.py +5 -6
  621. localstack/utils/container_utils/container_client.py +156 -160
  622. localstack/utils/container_utils/docker_cmd_client.py +97 -81
  623. localstack/utils/container_utils/docker_sdk_client.py +75 -72
  624. localstack/utils/crypto.py +12 -13
  625. localstack/utils/diagnose.py +11 -12
  626. localstack/utils/docker_utils.py +11 -7
  627. localstack/utils/files.py +34 -15
  628. localstack/utils/functions.py +5 -4
  629. localstack/utils/http.py +14 -14
  630. localstack/utils/iputils.py +2 -1
  631. localstack/utils/json.py +21 -7
  632. localstack/utils/kinesis/kinesis_connector.py +2 -1
  633. localstack/utils/net.py +25 -17
  634. localstack/utils/no_exit_argument_parser.py +2 -2
  635. localstack/utils/numbers.py +9 -2
  636. localstack/utils/objects.py +15 -14
  637. localstack/utils/patch.py +14 -7
  638. localstack/utils/platform.py +2 -2
  639. localstack/utils/run.py +15 -14
  640. localstack/utils/scheduler.py +13 -12
  641. localstack/utils/server/tcp_proxy.py +2 -2
  642. localstack/utils/serving.py +3 -4
  643. localstack/utils/strings.py +15 -16
  644. localstack/utils/sync.py +126 -1
  645. localstack/utils/tagging.py +10 -8
  646. localstack/utils/testutil.py +17 -17
  647. localstack/utils/threads.py +3 -3
  648. localstack/utils/time.py +12 -4
  649. localstack/utils/urls.py +1 -3
  650. localstack/utils/xml.py +1 -1
  651. localstack/utils/xray/traceid.py +1 -1
  652. localstack/version.py +16 -3
  653. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/METADATA +18 -13
  654. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/RECORD +663 -655
  655. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/entry_points.txt +8 -4
  656. localstack_core-4.10.1.dev12.dist-info/plux.json +1 -0
  657. localstack/packages/terraform.py +0 -47
  658. localstack/services/cloudformation/deploy.html +0 -144
  659. localstack/services/cloudformation/deploy_ui.py +0 -47
  660. localstack/services/cloudformation/plugins.py +0 -12
  661. localstack/services/lambda_/lambda_debug_mode/ldm.py +0 -375
  662. localstack/services/lambda_/lambda_debug_mode/ldm_config_file.py +0 -178
  663. localstack/services/lambda_/lambda_debug_mode/ldm_types.py +0 -11
  664. localstack/services/lambda_/lambda_debug_mode/ldm_utils.py +0 -43
  665. localstack_core-4.6.1.dev60.dist-info/plux.json +0 -1
  666. /localstack/{services/lambda_/lambda_debug_mode/__init__.py → testing/pytest/cloudformation/transformers.py} +0 -0
  667. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack +0 -0
  668. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack-supervisor +0 -0
  669. {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack.bat +0 -0
  670. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/WHEEL +0 -0
  671. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/licenses/LICENSE.txt +0 -0
  672. {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/top_level.txt +0 -0
@@ -2,12 +2,19 @@ from __future__ import annotations
2
2
 
3
3
  import abc
4
4
  import enum
5
+ from collections.abc import Generator
5
6
  from itertools import zip_longest
6
- from typing import Any, Final, Generator, Optional, TypedDict, Union, cast
7
+ from typing import Any, Final, TypedDict, cast
7
8
 
8
9
  from typing_extensions import TypeVar
9
10
 
10
11
  from localstack.aws.api.cloudformation import ChangeAction
12
+ from localstack.services.cloudformation.resource_provider import ResourceProviderExecutor
13
+ from localstack.services.cloudformation.v2.types import (
14
+ EngineParameter,
15
+ engine_parameter_value,
16
+ )
17
+ from localstack.utils.json import extract_jsonpath
11
18
  from localstack.utils.strings import camel_to_snake_case
12
19
 
13
20
  T = TypeVar("T")
@@ -43,7 +50,7 @@ class NothingType:
43
50
  return False
44
51
 
45
52
 
46
- Maybe = Union[T, NothingType]
53
+ Maybe = T | NothingType
47
54
  Nothing = NothingType()
48
55
 
49
56
 
@@ -63,6 +70,9 @@ def parent_change_type_of(children: list[Maybe[ChangeSetEntity]]):
63
70
  change_types = [c.change_type for c in children if not is_nothing(c)]
64
71
  if not change_types:
65
72
  return ChangeType.UNCHANGED
73
+ # TODO: rework this logic. Currently if any values are different then we consider it
74
+ # modified, but e.g. if everything is unchanged or created, the result should probably be
75
+ # "created"
66
76
  first_type = change_types[0]
67
77
  if all(ct == first_type for ct in change_types):
68
78
  return first_type
@@ -85,7 +95,7 @@ class NormalisedGlobalTransformDefinition(TypedDict):
85
95
 
86
96
 
87
97
  class Scope(str):
88
- _ROOT_SCOPE: Final[str] = str()
98
+ _ROOT_SCOPE: Final[str] = ""
89
99
  _SEPARATOR: Final[str] = "/"
90
100
 
91
101
  def __new__(cls, scope: str = _ROOT_SCOPE) -> Scope:
@@ -100,6 +110,30 @@ class Scope(str):
100
110
  def unwrap(self) -> list[str]:
101
111
  return self.split(self._SEPARATOR)
102
112
 
113
+ @property
114
+ def parent(self) -> Scope:
115
+ return Scope(self._SEPARATOR.join(self.split(self._SEPARATOR)[:-1]))
116
+
117
+ @property
118
+ def jsonpath(self) -> str:
119
+ parts = self.split("/")
120
+ json_parts = []
121
+
122
+ for part in parts:
123
+ if not part: # Skip empty strings from leading/trailing slashes
124
+ continue
125
+
126
+ if part == "divergence":
127
+ continue
128
+
129
+ # Wrap keys with special characters (e.g., colon) in quotes
130
+ if ":" in part:
131
+ json_parts.append(f'"{part}"')
132
+ else:
133
+ json_parts.append(part)
134
+
135
+ return f"$.{'.'.join(json_parts)}"
136
+
103
137
 
104
138
  class ChangeType(enum.Enum):
105
139
  UNCHANGED = "Unchanged"
@@ -121,7 +155,7 @@ class ChangeType(enum.Enum):
121
155
 
122
156
  class ChangeSetEntity(abc.ABC):
123
157
  scope: Final[Scope]
124
- change_type: Final[ChangeType]
158
+ change_type: ChangeType
125
159
 
126
160
  def __init__(self, scope: Scope, change_type: ChangeType):
127
161
  self.scope = scope
@@ -168,8 +202,8 @@ class UpdateModel:
168
202
  node_template: NodeTemplate,
169
203
  ):
170
204
  self.node_template = node_template
171
- self.before_runtime_cache = dict()
172
- self.after_runtime_cache = dict()
205
+ self.before_runtime_cache = {}
206
+ self.after_runtime_cache = {}
173
207
 
174
208
 
175
209
  class NodeTemplate(ChangeSetNode):
@@ -337,11 +371,21 @@ class NodeTransform(ChangeSetNode):
337
371
 
338
372
  class NodeResources(ChangeSetNode):
339
373
  resources: Final[list[NodeResource]]
374
+ fn_transform: Final[Maybe[NodeIntrinsicFunctionFnTransform]]
375
+ fn_foreaches: Final[list[NodeForEach]]
340
376
 
341
- def __init__(self, scope: Scope, resources: list[NodeResource]):
342
- change_type = parent_change_type_of(resources)
377
+ def __init__(
378
+ self,
379
+ scope: Scope,
380
+ resources: list[NodeResource],
381
+ fn_transform: Maybe[NodeIntrinsicFunctionFnTransform],
382
+ fn_foreaches: list[NodeForEach],
383
+ ):
384
+ change_type = parent_change_type_of(resources + [fn_transform] + fn_foreaches)
343
385
  super().__init__(scope=scope, change_type=change_type)
344
386
  self.resources = resources
387
+ self.fn_transform = fn_transform
388
+ self.fn_foreaches = fn_foreaches
345
389
 
346
390
 
347
391
  class NodeResource(ChangeSetNode):
@@ -350,6 +394,10 @@ class NodeResource(ChangeSetNode):
350
394
  properties: Final[NodeProperties]
351
395
  condition_reference: Final[Maybe[TerminalValue]]
352
396
  depends_on: Final[Maybe[NodeDependsOn]]
397
+ requires_replacement: Final[bool]
398
+ deletion_policy: Final[Maybe[ChangeSetTerminal]]
399
+ update_replace_policy: Final[Maybe[ChangeSetTerminal]]
400
+ fn_transform: Final[Maybe[NodeIntrinsicFunctionFnTransform]]
353
401
 
354
402
  def __init__(
355
403
  self,
@@ -360,6 +408,10 @@ class NodeResource(ChangeSetNode):
360
408
  properties: NodeProperties,
361
409
  condition_reference: Maybe[TerminalValue],
362
410
  depends_on: Maybe[NodeDependsOn],
411
+ requires_replacement: bool,
412
+ deletion_policy: Maybe[ChangeSetTerminal],
413
+ update_replace_policy: Maybe[ChangeSetTerminal],
414
+ fn_transform: Maybe[NodeIntrinsicFunctionFnTransform],
363
415
  ):
364
416
  super().__init__(scope=scope, change_type=change_type)
365
417
  self.name = name
@@ -367,15 +419,26 @@ class NodeResource(ChangeSetNode):
367
419
  self.properties = properties
368
420
  self.condition_reference = condition_reference
369
421
  self.depends_on = depends_on
422
+ self.requires_replacement = requires_replacement
423
+ self.deletion_policy = deletion_policy
424
+ self.update_replace_policy = update_replace_policy
425
+ self.fn_transform = fn_transform
370
426
 
371
427
 
372
428
  class NodeProperties(ChangeSetNode):
373
429
  properties: Final[list[NodeProperty]]
430
+ fn_transform: Final[Maybe[NodeIntrinsicFunctionFnTransform]]
374
431
 
375
- def __init__(self, scope: Scope, properties: list[NodeProperty]):
432
+ def __init__(
433
+ self,
434
+ scope: Scope,
435
+ properties: list[NodeProperty],
436
+ fn_transform: Maybe[NodeIntrinsicFunctionFnTransform],
437
+ ):
376
438
  change_type = parent_change_type_of(properties)
377
439
  super().__init__(scope=scope, change_type=change_type)
378
440
  self.properties = properties
441
+ self.fn_transform = fn_transform
379
442
 
380
443
 
381
444
  class NodeDependsOn(ChangeSetNode):
@@ -412,6 +475,40 @@ class NodeIntrinsicFunction(ChangeSetNode):
412
475
  self.arguments = arguments
413
476
 
414
477
 
478
+ class NodeIntrinsicFunctionFnTransform(NodeIntrinsicFunction):
479
+ def __init__(
480
+ self,
481
+ scope: Scope,
482
+ change_type: ChangeType,
483
+ intrinsic_function: str,
484
+ arguments: ChangeSetEntity,
485
+ before_siblings: list[Any],
486
+ after_siblings: list[Any],
487
+ ):
488
+ super().__init__(
489
+ scope=scope,
490
+ change_type=change_type,
491
+ intrinsic_function=intrinsic_function,
492
+ arguments=arguments,
493
+ )
494
+ self.before_siblings = before_siblings
495
+ self.after_siblings = after_siblings
496
+
497
+
498
+ class NodeForEach(ChangeSetNode):
499
+ def __init__(
500
+ self,
501
+ scope: Scope,
502
+ change_type: Final[ChangeType],
503
+ arguments: Final[ChangeSetEntity],
504
+ ):
505
+ super().__init__(
506
+ scope=scope,
507
+ change_type=change_type,
508
+ )
509
+ self.arguments = arguments
510
+
511
+
415
512
  class NodeObject(ChangeSetNode):
416
513
  bindings: Final[dict[str, ChangeSetEntity]]
417
514
 
@@ -473,6 +570,8 @@ ValueKey: Final[str] = "Value"
473
570
  ExportKey: Final[str] = "Export"
474
571
  OutputsKey: Final[str] = "Outputs"
475
572
  DependsOnKey: Final[str] = "DependsOn"
573
+ DeletionPolicyKey: Final[str] = "DeletionPolicy"
574
+ UpdateReplacePolicyKey: Final[str] = "UpdateReplacePolicy"
476
575
  # TODO: expand intrinsic functions set.
477
576
  RefKey: Final[str] = "Ref"
478
577
  RefConditionKey: Final[str] = "Condition"
@@ -490,6 +589,7 @@ FnSelect: Final[str] = "Fn::Select"
490
589
  FnSplit: Final[str] = "Fn::Split"
491
590
  FnGetAZs: Final[str] = "Fn::GetAZs"
492
591
  FnBase64: Final[str] = "Fn::Base64"
592
+ FnImportValue: Final[str] = "Fn::ImportValue"
493
593
  INTRINSIC_FUNCTIONS: Final[set[str]] = {
494
594
  RefKey,
495
595
  RefConditionKey,
@@ -507,6 +607,7 @@ INTRINSIC_FUNCTIONS: Final[set[str]] = {
507
607
  FnSplit,
508
608
  FnGetAZs,
509
609
  FnBase64,
610
+ FnImportValue,
510
611
  }
511
612
 
512
613
 
@@ -527,16 +628,17 @@ class ChangeSetModel:
527
628
 
528
629
  def __init__(
529
630
  self,
530
- before_template: Optional[dict],
531
- after_template: Optional[dict],
532
- before_parameters: Optional[dict],
533
- after_parameters: Optional[dict],
631
+ before_template: dict | None,
632
+ after_template: dict | None,
633
+ before_parameters: dict | None,
634
+ after_parameters: dict[str, EngineParameter] | None,
534
635
  ):
535
636
  self._before_template = before_template or Nothing
536
637
  self._after_template = after_template or Nothing
537
638
  self._before_parameters = before_parameters or Nothing
538
639
  self._after_parameters = after_parameters or Nothing
539
- self._visited_scopes = dict()
640
+ self._visited_scopes = {}
641
+ # TODO: move this modeling process to the `get_update_model` method as constructors shouldn't do work
540
642
  self._node_template = self._model(
541
643
  before_template=self._before_template, after_template=self._after_template
542
644
  )
@@ -578,6 +680,7 @@ class ChangeSetModel:
578
680
  arguments = self._visit_value(
579
681
  scope=arguments_scope, before_value=before_arguments, after_value=after_arguments
580
682
  )
683
+
581
684
  if is_created(before=before_arguments, after=after_arguments):
582
685
  change_type = ChangeType.CREATED
583
686
  elif is_removed(before=before_arguments, after=after_arguments):
@@ -591,15 +694,47 @@ class ChangeSetModel:
591
694
  change_type = resolve_function(arguments)
592
695
  else:
593
696
  change_type = arguments.change_type
594
- node_intrinsic_function = NodeIntrinsicFunction(
595
- scope=scope,
596
- change_type=change_type,
597
- intrinsic_function=intrinsic_function,
598
- arguments=arguments,
599
- )
697
+
698
+ if intrinsic_function == FnTransform:
699
+ if scope.count(FnTransform) > 1:
700
+ raise RuntimeError(
701
+ "Invalid: Fn::Transforms cannot be nested inside another Fn::Transform"
702
+ )
703
+
704
+ path = scope.parent.jsonpath
705
+ before_siblings = extract_jsonpath(self._before_template, path)
706
+ after_siblings = extract_jsonpath(self._after_template, path)
707
+
708
+ node_intrinsic_function = NodeIntrinsicFunctionFnTransform(
709
+ scope=scope,
710
+ change_type=change_type,
711
+ arguments=arguments,
712
+ intrinsic_function=intrinsic_function,
713
+ before_siblings=before_siblings,
714
+ after_siblings=after_siblings,
715
+ )
716
+ else:
717
+ node_intrinsic_function = NodeIntrinsicFunction(
718
+ scope=scope,
719
+ change_type=change_type,
720
+ intrinsic_function=intrinsic_function,
721
+ arguments=arguments,
722
+ )
600
723
  self._visited_scopes[scope] = node_intrinsic_function
601
724
  return node_intrinsic_function
602
725
 
726
+ def _visit_foreach(
727
+ self, scope: Scope, before_arguments: Maybe[list], after_arguments: Maybe[list]
728
+ ) -> NodeForEach:
729
+ node_foreach = self._visited_scopes.get(scope)
730
+ if isinstance(node_foreach, NodeForEach):
731
+ return node_foreach
732
+ arguments_scope = scope.open_scope("args")
733
+ arguments = self._visit_array(
734
+ arguments_scope, before_array=before_arguments, after_array=after_arguments
735
+ )
736
+ return NodeForEach(scope=scope, change_type=arguments.change_type, arguments=arguments)
737
+
603
738
  def _resolve_intrinsic_function_fn_sub(self, arguments: ChangeSetEntity) -> ChangeType:
604
739
  # TODO: This routine should instead export the implicit Ref and GetAtt calls within the first
605
740
  # string template parameter and compute the respective change set types. Currently,
@@ -647,6 +782,9 @@ class ChangeSetModel:
647
782
 
648
783
  logical_id = arguments.value
649
784
 
785
+ if isinstance(logical_id, str) and logical_id.startswith("AWS::"):
786
+ return arguments.change_type
787
+
650
788
  node_condition = self._retrieve_condition_if_exists(condition_name=logical_id)
651
789
  if isinstance(node_condition, NodeCondition):
652
790
  return node_condition.change_type
@@ -717,13 +855,38 @@ class ChangeSetModel:
717
855
  )
718
856
  if not isinstance(node_condition, NodeCondition):
719
857
  raise RuntimeError()
720
- change_type = parent_change_type_of([node_condition, *arguments[1:]])
858
+ change_type = parent_change_type_of([node_condition, *arguments.array[1:]])
721
859
  return change_type
722
860
 
861
+ def _resolve_requires_replacement(
862
+ self, node_properties: NodeProperties, resource_type: TerminalValue
863
+ ) -> bool:
864
+ # a bit hacky but we have to load the resource provider executor _and_ resource provider to get the schema
865
+ # Note: we don't log the attempt to load the resource provider, we need to make sure this is only done once and we already do this in the executor
866
+
867
+ resource_provider = ResourceProviderExecutor.try_load_resource_provider(resource_type.value)
868
+ if not resource_provider:
869
+ # if we don't support a resource, assume an in-place update for simplicity
870
+ return False
871
+
872
+ create_only_properties: list[str] = resource_provider.SCHEMA.get("createOnlyProperties", [])
873
+ # TODO: also hacky: strip the leading `/properties/` string from the definition
874
+ # ideally we should use a jsonpath or similar
875
+ create_only_properties = [
876
+ property.replace("/properties/", "", 1) for property in create_only_properties
877
+ ]
878
+ for node_property in node_properties.properties:
879
+ if (
880
+ node_property.change_type == ChangeType.MODIFIED
881
+ and node_property.name in create_only_properties
882
+ ):
883
+ return True
884
+ return False
885
+
723
886
  def _visit_array(
724
887
  self, scope: Scope, before_array: Maybe[list], after_array: Maybe[list]
725
888
  ) -> NodeArray:
726
- array: list[ChangeSetEntity] = list()
889
+ array: list[ChangeSetEntity] = []
727
890
  for index, (before_value, after_value) in enumerate(
728
891
  zip_longest(before_array, after_array, fillvalue=Nothing)
729
892
  ):
@@ -742,7 +905,7 @@ class ChangeSetModel:
742
905
  if isinstance(node_object, NodeObject):
743
906
  return node_object
744
907
  binding_names = self._safe_keys_of(before_object, after_object)
745
- bindings: dict[str, ChangeSetEntity] = dict()
908
+ bindings: dict[str, ChangeSetEntity] = {}
746
909
  for binding_name in binding_names:
747
910
  binding_scope, (before_value, after_value) = self._safe_access_in(
748
911
  scope, binding_name, before_object, after_object
@@ -844,11 +1007,19 @@ class ChangeSetModel:
844
1007
  if isinstance(node_properties, NodeProperties):
845
1008
  return node_properties
846
1009
  property_names: list[str] = self._safe_keys_of(before_properties, after_properties)
847
- properties: list[NodeProperty] = list()
1010
+ properties: list[NodeProperty] = []
1011
+ fn_transform = Nothing
1012
+
848
1013
  for property_name in property_names:
849
1014
  property_scope, (before_property, after_property) = self._safe_access_in(
850
1015
  scope, property_name, before_properties, after_properties
851
1016
  )
1017
+ if property_name == FnTransform:
1018
+ fn_transform = self._visit_intrinsic_function(
1019
+ property_scope, FnTransform, before_property, after_property
1020
+ )
1021
+ continue
1022
+
852
1023
  property_ = self._visit_property(
853
1024
  scope=property_scope,
854
1025
  property_name=property_name,
@@ -856,7 +1027,10 @@ class ChangeSetModel:
856
1027
  after_property=after_property,
857
1028
  )
858
1029
  properties.append(property_)
859
- node_properties = NodeProperties(scope=scope, properties=properties)
1030
+
1031
+ node_properties = NodeProperties(
1032
+ scope=scope, properties=properties, fn_transform=fn_transform
1033
+ )
860
1034
  self._visited_scopes[scope] = node_properties
861
1035
  return node_properties
862
1036
 
@@ -867,6 +1041,30 @@ class ChangeSetModel:
867
1041
  raise RuntimeError()
868
1042
  return value
869
1043
 
1044
+ def _visit_deletion_policy(
1045
+ self, scope: Scope, before_deletion_policy: Any, after_deletion_policy: Any
1046
+ ) -> TerminalValue:
1047
+ value = self._visit_value(
1048
+ scope=scope, before_value=before_deletion_policy, after_value=after_deletion_policy
1049
+ )
1050
+ if not isinstance(value, TerminalValue):
1051
+ # TODO: decide where template schema validation should occur.
1052
+ raise RuntimeError()
1053
+ return value
1054
+
1055
+ def _visit_update_replace_policy(
1056
+ self, scope: Scope, before_update_replace_policy: Any, after_deletion_policy: Any
1057
+ ) -> TerminalValue:
1058
+ value = self._visit_value(
1059
+ scope=scope,
1060
+ before_value=before_update_replace_policy,
1061
+ after_value=after_deletion_policy,
1062
+ )
1063
+ if not isinstance(value, TerminalValue):
1064
+ # TODO: decide where template schema validation should occur.
1065
+ raise RuntimeError()
1066
+ return value
1067
+
870
1068
  def _visit_resource(
871
1069
  self,
872
1070
  scope: Scope,
@@ -912,8 +1110,67 @@ class ChangeSetModel:
912
1110
  after_properties=after_properties,
913
1111
  )
914
1112
 
1113
+ deletion_policy = Nothing
1114
+ scope_deletion_policy, (before_deletion_policy, after_deletion_policy) = (
1115
+ self._safe_access_in(scope, DeletionPolicyKey, before_resource, after_resource)
1116
+ )
1117
+ if before_deletion_policy or after_deletion_policy:
1118
+ deletion_policy = self._visit_deletion_policy(
1119
+ scope_deletion_policy, before_deletion_policy, after_deletion_policy
1120
+ )
1121
+
1122
+ update_replace_policy = Nothing
1123
+ scope_update_replace_policy, (before_update_replace_policy, after_update_replace_policy) = (
1124
+ self._safe_access_in(scope, UpdateReplacePolicyKey, before_resource, after_resource)
1125
+ )
1126
+ if before_update_replace_policy or after_update_replace_policy:
1127
+ update_replace_policy = self._visit_update_replace_policy(
1128
+ scope_update_replace_policy,
1129
+ before_update_replace_policy,
1130
+ after_update_replace_policy,
1131
+ )
1132
+
1133
+ fn_transform = Nothing
1134
+ scope_fn_transform, (before_fn_transform_args, after_fn_transform_args) = (
1135
+ self._safe_access_in(scope, FnTransform, before_resource, after_resource)
1136
+ )
1137
+ if not is_nothing(before_fn_transform_args) or not is_nothing(after_fn_transform_args):
1138
+ if scope_fn_transform.count(FnTransform) > 1:
1139
+ raise RuntimeError(
1140
+ "Invalid: Fn::Transforms cannot be nested inside another Fn::Transform"
1141
+ )
1142
+ path = "$" + ".".join(scope_fn_transform.split("/")[:-1])
1143
+ before_siblings = extract_jsonpath(self._before_template, path)
1144
+ after_siblings = extract_jsonpath(self._after_template, path)
1145
+ arguments_scope = scope.open_scope("args")
1146
+ arguments = self._visit_value(
1147
+ scope=arguments_scope,
1148
+ before_value=before_fn_transform_args,
1149
+ after_value=after_fn_transform_args,
1150
+ )
1151
+ fn_transform = NodeIntrinsicFunctionFnTransform(
1152
+ scope=scope_fn_transform,
1153
+ change_type=ChangeType.MODIFIED, # TODO
1154
+ arguments=arguments, # TODO
1155
+ intrinsic_function=FnTransform,
1156
+ before_siblings=before_siblings,
1157
+ after_siblings=after_siblings,
1158
+ )
1159
+
915
1160
  change_type = change_type_of(
916
- before_resource, after_resource, [properties, condition_reference, depends_on]
1161
+ before_resource,
1162
+ after_resource,
1163
+ [
1164
+ properties,
1165
+ condition_reference,
1166
+ depends_on,
1167
+ deletion_policy,
1168
+ update_replace_policy,
1169
+ fn_transform,
1170
+ ],
1171
+ )
1172
+ requires_replacement = self._resolve_requires_replacement(
1173
+ node_properties=properties, resource_type=terminal_value_type
917
1174
  )
918
1175
  node_resource = NodeResource(
919
1176
  scope=scope,
@@ -923,6 +1180,10 @@ class ChangeSetModel:
923
1180
  properties=properties,
924
1181
  condition_reference=condition_reference,
925
1182
  depends_on=depends_on,
1183
+ requires_replacement=requires_replacement,
1184
+ deletion_policy=deletion_policy,
1185
+ update_replace_policy=update_replace_policy,
1186
+ fn_transform=fn_transform,
926
1187
  )
927
1188
  self._visited_scopes[scope] = node_resource
928
1189
  return node_resource
@@ -931,12 +1192,30 @@ class ChangeSetModel:
931
1192
  self, scope: Scope, before_resources: Maybe[dict], after_resources: Maybe[dict]
932
1193
  ) -> NodeResources:
933
1194
  # TODO: investigate type changes behavior.
934
- resources: list[NodeResource] = list()
1195
+ resources: list[NodeResource] = []
935
1196
  resource_names = self._safe_keys_of(before_resources, after_resources)
1197
+ fn_transform = Nothing
1198
+ fn_foreaches = []
936
1199
  for resource_name in resource_names:
937
1200
  resource_scope, (before_resource, after_resource) = self._safe_access_in(
938
1201
  scope, resource_name, before_resources, after_resources
939
1202
  )
1203
+ if resource_name == FnTransform:
1204
+ fn_transform = self._visit_intrinsic_function(
1205
+ scope=resource_scope,
1206
+ intrinsic_function=resource_name,
1207
+ before_arguments=before_resource,
1208
+ after_arguments=after_resource,
1209
+ )
1210
+ continue
1211
+ elif resource_name.startswith("Fn::ForEach"):
1212
+ fn_for_each = self._visit_foreach(
1213
+ scope=resource_scope,
1214
+ before_arguments=before_resource,
1215
+ after_arguments=after_resource,
1216
+ )
1217
+ fn_foreaches.append(fn_for_each)
1218
+ continue
940
1219
  resource = self._visit_resource(
941
1220
  scope=resource_scope,
942
1221
  resource_name=resource_name,
@@ -944,7 +1223,12 @@ class ChangeSetModel:
944
1223
  after_resource=after_resource,
945
1224
  )
946
1225
  resources.append(resource)
947
- return NodeResources(scope=scope, resources=resources)
1226
+ return NodeResources(
1227
+ scope=scope,
1228
+ resources=resources,
1229
+ fn_transform=fn_transform,
1230
+ fn_foreaches=fn_foreaches,
1231
+ )
948
1232
 
949
1233
  def _visit_mapping(
950
1234
  self, scope: Scope, name: str, before_mapping: Maybe[dict], after_mapping: Maybe[dict]
@@ -957,7 +1241,7 @@ class ChangeSetModel:
957
1241
  def _visit_mappings(
958
1242
  self, scope: Scope, before_mappings: Maybe[dict], after_mappings: Maybe[dict]
959
1243
  ) -> NodeMappings:
960
- mappings: list[NodeMapping] = list()
1244
+ mappings: list[NodeMapping] = []
961
1245
  mapping_names = self._safe_keys_of(before_mappings, after_mappings)
962
1246
  for mapping_name in mapping_names:
963
1247
  scope_mapping, (before_mapping, after_mapping) = self._safe_access_in(
@@ -974,9 +1258,22 @@ class ChangeSetModel:
974
1258
 
975
1259
  def _visit_dynamic_parameter(self, parameter_name: str) -> ChangeSetEntity:
976
1260
  scope = Scope("Dynamic").open_scope("Parameters")
977
- scope_parameter, (before_parameter, after_parameter) = self._safe_access_in(
1261
+ scope_parameter, (before_parameter_dct, after_parameter_dct) = self._safe_access_in(
978
1262
  scope, parameter_name, self._before_parameters, self._after_parameters
979
1263
  )
1264
+
1265
+ before_parameter = Nothing
1266
+ if not is_nothing(before_parameter_dct):
1267
+ before_parameter = before_parameter_dct.get("resolved_value") or engine_parameter_value(
1268
+ before_parameter_dct
1269
+ )
1270
+
1271
+ after_parameter = Nothing
1272
+ if not is_nothing(after_parameter_dct):
1273
+ after_parameter = after_parameter_dct.get("resolved_value") or engine_parameter_value(
1274
+ after_parameter_dct
1275
+ )
1276
+
980
1277
  parameter = self._visit_value(
981
1278
  scope=scope_parameter, before_value=before_parameter, after_value=after_parameter
982
1279
  )
@@ -1022,7 +1319,7 @@ class ChangeSetModel:
1022
1319
  if isinstance(node_parameters, NodeParameters):
1023
1320
  return node_parameters
1024
1321
  parameter_names: list[str] = self._safe_keys_of(before_parameters, after_parameters)
1025
- parameters: list[NodeParameter] = list()
1322
+ parameters: list[NodeParameter] = []
1026
1323
  for parameter_name in parameter_names:
1027
1324
  parameter_scope, (before_parameter, after_parameter) = self._safe_access_in(
1028
1325
  scope, parameter_name, before_parameters, after_parameters
@@ -1092,7 +1389,7 @@ class ChangeSetModel:
1092
1389
  if isinstance(node_conditions, NodeConditions):
1093
1390
  return node_conditions
1094
1391
  condition_names: list[str] = self._safe_keys_of(before_conditions, after_conditions)
1095
- conditions: list[NodeCondition] = list()
1392
+ conditions: list[NodeCondition] = []
1096
1393
  for condition_name in condition_names:
1097
1394
  condition_scope, (before_condition, after_condition) = self._safe_access_in(
1098
1395
  scope, condition_name, before_conditions, after_conditions
@@ -1144,7 +1441,7 @@ class ChangeSetModel:
1144
1441
  def _visit_outputs(
1145
1442
  self, scope: Scope, before_outputs: Maybe[dict], after_outputs: Maybe[dict]
1146
1443
  ) -> NodeOutputs:
1147
- outputs: list[NodeOutput] = list()
1444
+ outputs: list[NodeOutput] = []
1148
1445
  output_names: list[str] = self._safe_keys_of(before_outputs, after_outputs)
1149
1446
  for output_name in output_names:
1150
1447
  scope_output, (before_output, after_output) = self._safe_access_in(
@@ -1191,7 +1488,7 @@ class ChangeSetModel:
1191
1488
  elif isinstance(value, str):
1192
1489
  value = [NormalisedGlobalTransformDefinition(Name=value, Parameters=Nothing)]
1193
1490
  elif isinstance(value, list):
1194
- tmp_value = list()
1491
+ tmp_value = []
1195
1492
  for item in value:
1196
1493
  if isinstance(item, str):
1197
1494
  tmp_value.append(
@@ -1215,7 +1512,7 @@ class ChangeSetModel:
1215
1512
  ) -> NodeTransform:
1216
1513
  before_transform_normalised = self._normalise_transformer_value(before_transform)
1217
1514
  after_transform_normalised = self._normalise_transformer_value(after_transform)
1218
- global_transforms = list()
1515
+ global_transforms = []
1219
1516
  for index, (before_global_transform, after_global_transform) in enumerate(
1220
1517
  zip_longest(before_transform_normalised, after_transform_normalised, fillvalue=Nothing)
1221
1518
  ):
@@ -1296,8 +1593,8 @@ class ChangeSetModel:
1296
1593
  conditions_scope, (before_conditions, after_conditions) = self._safe_access_in(
1297
1594
  Scope(), ConditionsKey, self._before_template, self._after_template
1298
1595
  )
1299
- before_conditions = before_conditions or dict()
1300
- after_conditions = after_conditions or dict()
1596
+ before_conditions = before_conditions or {}
1597
+ after_conditions = after_conditions or {}
1301
1598
  if condition_name in before_conditions or condition_name in after_conditions:
1302
1599
  condition_scope, (before_condition, after_condition) = self._safe_access_in(
1303
1600
  conditions_scope, condition_name, before_conditions, after_conditions
@@ -1367,7 +1664,7 @@ class ChangeSetModel:
1367
1664
 
1368
1665
  @staticmethod
1369
1666
  def _safe_access_in(scope: Scope, key: str, *objects: Maybe[dict]) -> tuple[Scope, Maybe[Any]]:
1370
- results = list()
1667
+ results = []
1371
1668
  for obj in objects:
1372
1669
  if not isinstance(obj, (dict, NothingType)):
1373
1670
  raise RuntimeError(f"Invalid definition type at '{obj}'")
@@ -1391,7 +1688,7 @@ class ChangeSetModel:
1391
1688
  return keys
1392
1689
 
1393
1690
  @staticmethod
1394
- def _name_if_intrinsic_function(value: Maybe[Any]) -> Optional[str]:
1691
+ def _name_if_intrinsic_function(value: Maybe[Any]) -> str | None:
1395
1692
  if isinstance(value, dict):
1396
1693
  keys = ChangeSetModel._safe_keys_of(value)
1397
1694
  if len(keys) == 1: