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
@@ -14,27 +14,34 @@ The different protocols have many similarities. The class hierarchy is
14
14
  designed such that the serializers share as much logic as possible.
15
15
  The class hierarchy looks as follows:
16
16
  ::
17
- ┌───────────────────┐
18
- │ResponseSerializer │
19
- └───────────────────┘
20
- ▲ ▲
21
- ┌──────────────────────┘ └──────────────────┐
22
- ┌────────────┴────────────┐ ┌────────────┴─────────────┐ ┌─────────┴────────────┐
23
- │BaseXMLResponseSerializer│ BaseRestResponseSerializerJSONResponseSerializer│
24
- └─────────────────────────┘ └──────────────────────────┘ └──────────────────────┘
25
- ▲ ▲
26
- ┌──────────────────────┴─┐ ┌┴─────────────┴──────────┐ ┌┴──────────────┴──────────┐
27
- QueryResponseSerializer RestXMLResponseSerializer RestJSONResponseSerializer│
28
- └────────────────────────┘ └─────────────────────────┘ └──────────────────────────┘
29
-
30
- ┌──────────┴──────────┐
17
+ ┌────────────────────┐
18
+ ResponseSerializer │
19
+ └────────────────────┘
20
+ ▲ ▲
21
+ ┌─────────────────┬───────┘ └──────────────┬──────────────────────┐
22
+ ┌────────────┴────────────┐ │ ┌───────┴──────────────┐ │ ┌────────────┴─────────────┐
23
+ │BaseXMLResponseSerializer│ │JSONResponseSerializer│ │ │BaseCBORResponseSerializer│
24
+ └─────────────────────────┘ │ └──────────────────────┘ │ └──────────────────────────┘
25
+ ▲ ▲ ┌─────────────┴────────────┐ ┌─────┴─────────────────────┐
26
+ │ │ │BaseRestResponseSerializer│ │ │BaseRpcV2ResponseSerializer│ │ │
27
+ └──────────────────────────┘ └───────────────────────────┘
28
+ │ │ ▲ ▲ │ ▲ │ │
29
+ │ │ │ │ │ │ │ │
30
+ │ ┌─┴──────────────┴────────┐ ┌──┴───────────┴───────────┐ ┌──────────┴───────────┴────┐ │
31
+ │ │RestXMLResponseSerializer│ │RestJSONResponseSerializer│ │RpcV2CBORResponseSerializer│ │
32
+ │ └─────────────────────────┘ └──────────────────────────┘ └───────────────────────────┘ │
33
+ ┌─────┴──────────────────┐ ┌──────────┴─────────────┐
34
+ │QueryResponseSerializer │ │ CBORResponseSerializer │
35
+ └────────────────────────┘ └────────────────────────┘
36
+
37
+ ┌─────────┴───────────┐
31
38
  │EC2ResponseSerializer│
32
39
  └─────────────────────┘
33
40
  ::
34
41
 
35
42
  The ``ResponseSerializer`` contains the logic that is used among all the
36
- different protocols (``query``, ``json``, ``rest-json``, ``rest-xml``, and
37
- ``ec2``).
43
+ different protocols (``query``, ``json``, ``rest-json``, ``rest-xml``, ``cbor``
44
+ and ``ec2``).
38
45
  The protocols relate to each other in the following ways:
39
46
 
40
47
  * The ``query`` and the ``rest-xml`` protocols both have XML bodies in their
@@ -42,10 +49,14 @@ The protocols relate to each other in the following ways:
42
49
  type).
43
50
  * The ``json`` and the ``rest-json`` protocols both have JSON bodies in their
44
51
  responses which are serialized the same way.
52
+ * The ``cbor`` protocol is not properly defined in the spec, but mirrors the
53
+ ``json`` protocol.
45
54
  * The ``rest-json`` and ``rest-xml`` protocols serialize some metadata in
46
- the HTTP response's header fields
55
+ the HTTP response's header fields.
47
56
  * The ``ec2`` protocol is basically similar to the ``query`` protocol with a
48
57
  specific error response formatting.
58
+ * The ``smithy-rpc-v2-cbor`` protocol defines a specific way to route request
59
+ to services via the RPC v2 trait, and encodes its body with the CBOR format.
49
60
 
50
61
  The serializer classes in this module correspond directly to the different
51
62
  protocols. ``#create_serializer`` shows the explicit mapping between the
@@ -54,13 +65,23 @@ The classes are structured as follows:
54
65
 
55
66
  * The ``ResponseSerializer`` contains all the basic logic for the
56
67
  serialization which is shared among all different protocols.
57
- * The ``BaseXMLResponseSerializer`` and the ``JSONResponseSerializer``
58
- contain the logic for the XML and the JSON serialization respectively.
68
+ * The ``BaseXMLResponseSerializer``, ``JSONResponseSerializer`` and
69
+ ``BaseCBORResponseSerializer`` contain the logic for the XML, JSON
70
+ and the CBOR serialization respectively.
59
71
  * The ``BaseRestResponseSerializer`` contains the logic for the REST
60
72
  protocol specifics (i.e. specific HTTP header serializations).
73
+ * The ``BaseRpcV2ResponseSerializer`` contains the logic for the RPC v2
74
+ protocol specifics (i.e. pretty bare, does not has any specific
75
+ about body serialization).
61
76
  * The ``RestXMLResponseSerializer`` and the ``RestJSONResponseSerializer``
62
77
  inherit the ReST specific logic from the ``BaseRestResponseSerializer``
63
78
  and the XML / JSON body serialization from their second super class.
79
+ * The ``RpcV2CBORResponseSerializer`` inherits the RPC v2 specific logic
80
+ from the ``BaseRpcV2ResponseSerializer`` and the CBOR body serialization
81
+ from its second super class.
82
+ * The ``CBORResponseSerializer`` contains the logic specific to the
83
+ non-official ``cbor`` protocol, mirroring the ``json`` protocol but
84
+ with CBOR encoded body
64
85
 
65
86
  The services and their protocols are defined by using AWS's Smithy
66
87
  (a language to define services in a - somewhat - protocol-agnostic
@@ -73,20 +94,32 @@ be sent back to the calling client.
73
94
 
74
95
  import abc
75
96
  import base64
97
+ import datetime
76
98
  import functools
77
99
  import json
78
100
  import logging
101
+ import math
79
102
  import string
103
+ import struct
80
104
  from abc import ABC
81
105
  from binascii import crc32
82
- from datetime import datetime
106
+ from collections.abc import Iterable, Iterator
83
107
  from email.utils import formatdate
84
108
  from struct import pack
85
- from typing import Any, Dict, Iterable, Iterator, List, Optional, Tuple, Union
109
+ from typing import IO, Any
86
110
  from xml.etree import ElementTree as ETree
87
111
 
88
112
  import xmltodict
89
- from botocore.model import ListShape, MapShape, OperationModel, ServiceModel, Shape, StructureShape
113
+ from botocore.model import (
114
+ ListShape,
115
+ MapShape,
116
+ OperationModel,
117
+ ServiceModel,
118
+ Shape,
119
+ ShapeResolver,
120
+ StringShape,
121
+ StructureShape,
122
+ )
90
123
  from botocore.serialize import ISO8601, ISO8601_MICRO
91
124
  from botocore.utils import calculate_md5, is_json_value_header, parse_to_aware_datetime
92
125
 
@@ -181,14 +214,14 @@ class ResponseSerializer(abc.ABC):
181
214
  AWS_BINARY_DATA_TYPE_STRING = 7
182
215
  # Defines the supported mime types of the specific serializer. Sorted by priority (preferred / default first).
183
216
  # Needs to be specified by subclasses.
184
- SUPPORTED_MIME_TYPES: List[str] = []
217
+ SUPPORTED_MIME_TYPES: list[str] = []
185
218
 
186
219
  @_handle_exceptions
187
220
  def serialize_to_response(
188
221
  self,
189
222
  response: dict,
190
223
  operation_model: OperationModel,
191
- headers: Optional[Dict | Headers],
224
+ headers: dict | Headers | None,
192
225
  request_id: str,
193
226
  ) -> Response:
194
227
  """
@@ -234,7 +267,7 @@ class ResponseSerializer(abc.ABC):
234
267
  self,
235
268
  error: ServiceException,
236
269
  operation_model: OperationModel,
237
- headers: Optional[Dict | Headers],
270
+ headers: dict | Headers | None,
238
271
  request_id: str,
239
272
  ) -> Response:
240
273
  """
@@ -260,7 +293,11 @@ class ResponseSerializer(abc.ABC):
260
293
  f"Error to serialize ({error.__class__.__name__ if error else None}) is not a ServiceException."
261
294
  )
262
295
  shape = operation_model.service_model.shape_for_error_code(error.code)
263
- serialized_response.status_code = error.status_code
296
+ serialized_response.status_code = self._get_error_status_code(
297
+ error=error,
298
+ headers=headers,
299
+ service_model=operation_model.service_model,
300
+ )
264
301
 
265
302
  self._serialize_error(
266
303
  error, serialized_response, shape, operation_model, mime_type, request_id
@@ -274,7 +311,7 @@ class ResponseSerializer(abc.ABC):
274
311
  self,
275
312
  parameters: dict,
276
313
  response: Response,
277
- shape: Optional[Shape],
314
+ shape: Shape | None,
278
315
  shape_members: dict,
279
316
  operation_model: OperationModel,
280
317
  mime_type: str,
@@ -289,7 +326,7 @@ class ResponseSerializer(abc.ABC):
289
326
  operation_model: OperationModel,
290
327
  mime_type: str,
291
328
  request_id: str,
292
- ) -> Optional[str]:
329
+ ) -> str | None:
293
330
  """
294
331
  Actually serializes the given params for the given shape to a string for the transmission in the body of the
295
332
  response.
@@ -390,9 +427,9 @@ class ResponseSerializer(abc.ABC):
390
427
  def _encode_event_payload(
391
428
  self,
392
429
  event_type: str,
393
- content: Union[str, bytes] = "",
394
- error_code: Optional[str] = None,
395
- error_message: Optional[str] = None,
430
+ content: str | bytes = "",
431
+ error_code: str | None = None,
432
+ error_message: str | None = None,
396
433
  ) -> bytes:
397
434
  """
398
435
  Encodes the given event payload according to AWS specific binary event encoding.
@@ -469,7 +506,7 @@ class ResponseSerializer(abc.ABC):
469
506
  """
470
507
  return Response(status=operation_model.http.get("responseCode", 200))
471
508
 
472
- def _get_mime_type(self, headers: Optional[Dict | Headers]) -> str:
509
+ def _get_mime_type(self, headers: dict | Headers | None) -> str:
473
510
  """
474
511
  Extracts the accepted mime type from the request headers and returns a matching, supported mime type for the
475
512
  serializer or the default mime type of the service if there is no match.
@@ -505,7 +542,7 @@ class ResponseSerializer(abc.ABC):
505
542
  # Some extra utility methods subclasses can use.
506
543
 
507
544
  @staticmethod
508
- def _timestamp_iso8601(value: datetime) -> str:
545
+ def _timestamp_iso8601(value: datetime.datetime) -> str:
509
546
  if value.microsecond > 0:
510
547
  timestamp_format = ISO8601_MICRO
511
548
  else:
@@ -513,22 +550,22 @@ class ResponseSerializer(abc.ABC):
513
550
  return value.strftime(timestamp_format)
514
551
 
515
552
  @staticmethod
516
- def _timestamp_unixtimestamp(value: datetime) -> float:
553
+ def _timestamp_unixtimestamp(value: datetime.datetime) -> float:
517
554
  return value.timestamp()
518
555
 
519
- def _timestamp_rfc822(self, value: datetime) -> str:
520
- if isinstance(value, datetime):
556
+ def _timestamp_rfc822(self, value: datetime.datetime) -> str:
557
+ if isinstance(value, datetime.datetime):
521
558
  value = self._timestamp_unixtimestamp(value)
522
559
  return formatdate(value, usegmt=True)
523
560
 
524
561
  def _convert_timestamp_to_str(
525
- self, value: Union[int, str, datetime], timestamp_format=None
562
+ self, value: int | str | datetime.datetime, timestamp_format=None
526
563
  ) -> str:
527
564
  if timestamp_format is None:
528
565
  timestamp_format = self.TIMESTAMP_FORMAT
529
566
  timestamp_format = timestamp_format.lower()
530
567
  datetime_obj = parse_to_aware_datetime(value)
531
- converter = getattr(self, "_timestamp_%s" % timestamp_format)
568
+ converter = getattr(self, f"_timestamp_{timestamp_format}")
532
569
  final_value = converter(datetime_obj)
533
570
  return final_value
534
571
 
@@ -540,7 +577,7 @@ class ResponseSerializer(abc.ABC):
540
577
  """
541
578
  return shape.serialization.get("name", default_name)
542
579
 
543
- def _get_base64(self, value: Union[str, bytes]):
580
+ def _get_base64(self, value: str | bytes):
544
581
  """
545
582
  Returns the base64-encoded version of value, handling
546
583
  both strings and bytes. The returned value is a string
@@ -550,7 +587,7 @@ class ResponseSerializer(abc.ABC):
550
587
  value = value.encode(self.DEFAULT_ENCODING)
551
588
  return base64.b64encode(value).strip().decode(self.DEFAULT_ENCODING)
552
589
 
553
- def _encode_payload(self, body: Union[bytes, str]) -> bytes:
590
+ def _encode_payload(self, body: bytes | str) -> bytes:
554
591
  if isinstance(body, str):
555
592
  return body.encode(self.DEFAULT_ENCODING)
556
593
  return body
@@ -578,9 +615,63 @@ class ResponseSerializer(abc.ABC):
578
615
  md5_digest = calculate_md5(body)
579
616
  headers["Content-MD5"] = md5_digest
580
617
 
581
- def _get_error_message(self, error: Exception) -> Optional[str]:
618
+ def _get_error_message(self, error: Exception) -> str | None:
582
619
  return str(error) if error is not None and str(error) != "None" else None
583
620
 
621
+ def _get_error_status_code(
622
+ self, error: ServiceException, headers: Headers, service_model: ServiceModel
623
+ ) -> int:
624
+ return error.status_code
625
+
626
+
627
+ class QueryCompatibleProtocolMixin:
628
+ def _get_error_status_code(
629
+ self, error: ServiceException, headers: dict | Headers | None, service_model: ServiceModel
630
+ ) -> int:
631
+ # by default, some protocols (namely `json` and `smithy-rpc-v2-cbor`) might not define exception status code in
632
+ # their specs, so they are not defined in the `ServiceException` object and will use the default value of `400`
633
+ # But Query compatible service always do define them, so we get the wrong code for service that are
634
+ # multi-protocols like CloudWatch
635
+ # we need to verify if the service is compatible, and if the client has requested the query compatible error
636
+ # code to return the right value
637
+ if not service_model.is_query_compatible:
638
+ return error.status_code
639
+
640
+ if headers and headers.get("x-amzn-query-mode") == "true":
641
+ return error.status_code
642
+
643
+ # we only want to override status code 4XX
644
+ if 400 < error.status_code <= 499:
645
+ return 400
646
+
647
+ return error.status_code
648
+
649
+ def _add_query_compatible_error_header(self, response: Response, error: ServiceException):
650
+ """
651
+ Add an `x-amzn-query-error` header for client to translate errors codes from former `query` services
652
+ into other protocols.
653
+ """
654
+
655
+ sender_fault = "Sender" if error.sender_fault else "Receiver"
656
+ response.headers["x-amzn-query-error"] = f"{error.code};{sender_fault}"
657
+
658
+ def _get_error_code(
659
+ self, is_query_compatible: bool, error: ServiceException, shape: Shape | None = None
660
+ ):
661
+ # if the operation is query compatible, we need to add to use shape name
662
+ if is_query_compatible:
663
+ if shape:
664
+ code = shape.name
665
+ else:
666
+ # if the shape is not defined, we are using the Exception named to derive the `Code`, like you would
667
+ # from the shape. This allows us to have Exception that are valid in multi-protocols by defining its
668
+ # code and its name to be different
669
+ code = error.__class__.__name__
670
+ else:
671
+ code = error.code
672
+
673
+ return code
674
+
584
675
 
585
676
  class BaseXMLResponseSerializer(ResponseSerializer):
586
677
  """
@@ -661,14 +752,14 @@ class BaseXMLResponseSerializer(ResponseSerializer):
661
752
  operation_model: OperationModel,
662
753
  mime_type: str,
663
754
  request_id: str,
664
- ) -> Optional[str]:
755
+ ) -> str | None:
665
756
  root = self._serialize_body_params_to_xml(params, shape, operation_model, mime_type)
666
757
  self._prepare_additional_traits_in_xml(root, request_id)
667
758
  return self._node_to_string(root, mime_type)
668
759
 
669
760
  def _serialize_body_params_to_xml(
670
761
  self, params: dict, shape: Shape, operation_model: OperationModel, mime_type: str
671
- ) -> Optional[ETree.Element]:
762
+ ) -> ETree.Element | None:
672
763
  if shape is None:
673
764
  return
674
765
  # The botocore serializer expects `shape.serialization["name"]`, but this isn't always present for responses
@@ -690,7 +781,7 @@ class BaseXMLResponseSerializer(ResponseSerializer):
690
781
  name = shape.serialization.get("resultWrapper")
691
782
 
692
783
  try:
693
- method = getattr(self, "_serialize_type_%s" % shape.type_name, self._default_serialize)
784
+ method = getattr(self, f"_serialize_type_{shape.type_name}", self._default_serialize)
694
785
  method(xmlnode, params, shape, name, mime_type)
695
786
  except (TypeError, ValueError, AttributeError) as e:
696
787
  raise ProtocolSerializerError(
@@ -706,7 +797,7 @@ class BaseXMLResponseSerializer(ResponseSerializer):
706
797
  namespace_metadata = shape.serialization["xmlNamespace"]
707
798
  attribute_name = "xmlns"
708
799
  if namespace_metadata.get("prefix"):
709
- attribute_name += ":%s" % namespace_metadata["prefix"]
800
+ attribute_name += ":{}".format(namespace_metadata["prefix"])
710
801
  structure_node.attrib[attribute_name] = namespace_metadata["uri"]
711
802
  for key, value in params.items():
712
803
  if value is None:
@@ -812,7 +903,7 @@ class BaseXMLResponseSerializer(ResponseSerializer):
812
903
  node.text = str_value
813
904
 
814
905
  def _serialize_type_blob(
815
- self, xmlnode: ETree.Element, params: Union[str, bytes], _, name: str, __
906
+ self, xmlnode: ETree.Element, params: str | bytes, _, name: str, __
816
907
  ) -> None:
817
908
  node = ETree.SubElement(xmlnode, name)
818
909
  node.text = self._get_base64(params)
@@ -838,7 +929,7 @@ class BaseXMLResponseSerializer(ResponseSerializer):
838
929
  node = ETree.SubElement(xmlnode, name)
839
930
  node.text = str(params)
840
931
 
841
- def _prepare_additional_traits_in_xml(self, root: Optional[ETree.Element], request_id: str):
932
+ def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str):
842
933
  """
843
934
  Prepares the XML root node before being serialized with additional traits (like the Response ID in the Query
844
935
  protocol).
@@ -851,7 +942,7 @@ class BaseXMLResponseSerializer(ResponseSerializer):
851
942
  response.headers["Content-Type"] = mime_type
852
943
  return response
853
944
 
854
- def _node_to_string(self, root: Optional[ETree.Element], mime_type: str) -> Optional[str]:
945
+ def _node_to_string(self, root: ETree.Element | None, mime_type: str) -> str | None:
855
946
  """Generates the string representation of the given XML element."""
856
947
  if root is not None:
857
948
  content = ETree.tostring(
@@ -877,7 +968,7 @@ class BaseRestResponseSerializer(ResponseSerializer, ABC):
877
968
  self,
878
969
  parameters: dict,
879
970
  response: Response,
880
- shape: Optional[Shape],
971
+ shape: Shape | None,
881
972
  shape_members: dict,
882
973
  operation_model: OperationModel,
883
974
  mime_type: str,
@@ -904,7 +995,7 @@ class BaseRestResponseSerializer(ResponseSerializer, ABC):
904
995
  self,
905
996
  parameters: dict,
906
997
  response: Response,
907
- shape: Optional[Shape],
998
+ shape: Shape | None,
908
999
  shape_members: dict,
909
1000
  operation_model: OperationModel,
910
1001
  mime_type: str,
@@ -975,7 +1066,7 @@ class BaseRestResponseSerializer(ResponseSerializer, ABC):
975
1066
  """
976
1067
  pass
977
1068
 
978
- def _has_streaming_payload(self, payload: Optional[str], shape_members):
1069
+ def _has_streaming_payload(self, payload: str | None, shape_members):
979
1070
  """Determine if payload is streaming (a blob or string)."""
980
1071
  return payload is not None and shape_members[payload].type_name in ["blob", "string"]
981
1072
 
@@ -1040,7 +1131,7 @@ class BaseRestResponseSerializer(ResponseSerializer, ABC):
1040
1131
  else:
1041
1132
  return value
1042
1133
 
1043
- def _partition_members(self, parameters: dict, shape: Optional[Shape]) -> Tuple[dict, dict]:
1134
+ def _partition_members(self, parameters: dict, shape: Shape | None) -> tuple[dict, dict]:
1044
1135
  """Separates the top-level keys in the given parameters dict into header- and payload-located params."""
1045
1136
  if not isinstance(shape, StructureShape):
1046
1137
  # If the shape isn't a structure, we default to the whole response being parsed in the body.
@@ -1083,7 +1174,7 @@ class QueryResponseSerializer(BaseXMLResponseSerializer):
1083
1174
  self,
1084
1175
  parameters: dict,
1085
1176
  response: Response,
1086
- shape: Optional[Shape],
1177
+ shape: Shape | None,
1087
1178
  shape_members: dict,
1088
1179
  operation_model: OperationModel,
1089
1180
  mime_type: str,
@@ -1130,13 +1221,22 @@ class QueryResponseSerializer(BaseXMLResponseSerializer):
1130
1221
  root.append(node)
1131
1222
  return root
1132
1223
 
1133
- def _prepare_additional_traits_in_xml(self, root: Optional[ETree.Element], request_id: str):
1224
+ def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str):
1134
1225
  # Add the response metadata here (it's not defined in the specs)
1135
1226
  # For the ec2 and the query protocol, the root cannot be None at this time.
1136
1227
  response_metadata = ETree.SubElement(root, "ResponseMetadata")
1137
1228
  request_id_element = ETree.SubElement(response_metadata, "RequestId")
1138
1229
  request_id_element.text = request_id
1139
1230
 
1231
+ def _prepare_additional_traits_in_response(
1232
+ self, response: Response, operation_model: OperationModel, request_id: str
1233
+ ):
1234
+ response.headers["x-amzn-RequestId"] = request_id
1235
+ response = super()._prepare_additional_traits_in_response(
1236
+ response, operation_model, request_id
1237
+ )
1238
+ return response
1239
+
1140
1240
 
1141
1241
  class EC2ResponseSerializer(QueryResponseSerializer):
1142
1242
  """
@@ -1179,7 +1279,7 @@ class EC2ResponseSerializer(QueryResponseSerializer):
1179
1279
  request_id_element.text = request_id
1180
1280
  response.set_response(self._encode_payload(self._node_to_string(root, mime_type)))
1181
1281
 
1182
- def _prepare_additional_traits_in_xml(self, root: Optional[ETree.Element], request_id: str):
1282
+ def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str):
1183
1283
  # The EC2 protocol does not use the root output shape, therefore we need to remove the hierarchy level
1184
1284
  # below the root level
1185
1285
  if len(root) > 0:
@@ -1194,7 +1294,7 @@ class EC2ResponseSerializer(QueryResponseSerializer):
1194
1294
  request_id_element.text = request_id
1195
1295
 
1196
1296
 
1197
- class JSONResponseSerializer(ResponseSerializer):
1297
+ class JSONResponseSerializer(QueryCompatibleProtocolMixin, ResponseSerializer):
1198
1298
  """
1199
1299
  The ``JSONResponseSerializer`` is responsible for the serialization of responses from services with the ``json``
1200
1300
  protocol. It implements the JSON response body serialization, which is also used by the
@@ -1216,30 +1316,53 @@ class JSONResponseSerializer(ResponseSerializer):
1216
1316
  mime_type: str,
1217
1317
  request_id: str,
1218
1318
  ) -> None:
1219
- body = dict()
1319
+ body = {}
1220
1320
 
1221
1321
  # TODO implement different service-specific serializer configurations
1222
1322
  # - currently we set both, the `__type` member as well as the `X-Amzn-Errortype` header
1223
1323
  # - the specification defines that it's either the __type field OR the header
1224
- response.headers["X-Amzn-Errortype"] = error.code
1225
- body["__type"] = error.code
1324
+ # this depends on the JSON protocol version as well. If json-1.0 the Error should be the full shape ID, like
1325
+ # com.amazon.coral.service#ExceptionName
1326
+ # if json-1.1, it should only be the name
1327
+
1328
+ is_query_compatible = operation_model.service_model.is_query_compatible
1329
+ code = self._get_error_code(is_query_compatible, error, shape)
1330
+
1331
+ response.headers["X-Amzn-Errortype"] = code
1332
+
1333
+ # the `__type` field is not defined in default botocore error shapes
1334
+ body["__type"] = code
1226
1335
 
1227
1336
  if shape:
1228
1337
  remaining_params = {}
1229
1338
  # TODO add a possibility to serialize simple non-modelled errors (like S3 NoSuchBucket#BucketName)
1230
1339
  for member in shape.members:
1231
1340
  if hasattr(error, member):
1232
- remaining_params[member] = getattr(error, member)
1341
+ value = getattr(error, member)
1342
+
1233
1343
  # Default error message fields can sometimes have different casing in the specs
1234
1344
  elif member.lower() in ["code", "message"] and hasattr(error, member.lower()):
1235
- remaining_params[member] = getattr(error, member.lower())
1345
+ value = getattr(error, member.lower())
1346
+
1347
+ else:
1348
+ continue
1349
+
1350
+ if value is None:
1351
+ # do not serialize a value that is set to `None`
1352
+ continue
1353
+
1354
+ # if the value is falsy (empty string, empty list) and not in the Shape required members, AWS will
1355
+ # not serialize it, and it will not be part of the response body.
1356
+ if value or member in shape.required_members:
1357
+ remaining_params[member] = value
1358
+
1236
1359
  self._serialize(body, remaining_params, shape, None, mime_type)
1237
1360
 
1238
- # Only set the message if it has not been set with the shape members
1361
+ # this is a workaround, some Error Shape do not define a `Message` field, but it is always returned
1362
+ # this could be solved at the same time as the `__type` field
1239
1363
  if "message" not in body and "Message" not in body:
1240
- message = self._get_error_message(error)
1241
- if message is not None:
1242
- body["message"] = message
1364
+ if error_message := self._get_error_message(error):
1365
+ body["message"] = error_message
1243
1366
 
1244
1367
  if mime_type in self.CBOR_TYPES:
1245
1368
  response.set_response(cbor2_dumps(body, datetime_as_timestamp=True))
@@ -1247,11 +1370,14 @@ class JSONResponseSerializer(ResponseSerializer):
1247
1370
  else:
1248
1371
  response.set_json(body)
1249
1372
 
1373
+ if is_query_compatible:
1374
+ self._add_query_compatible_error_header(response, error)
1375
+
1250
1376
  def _serialize_response(
1251
1377
  self,
1252
1378
  parameters: dict,
1253
1379
  response: Response,
1254
- shape: Optional[Shape],
1380
+ shape: Shape | None,
1255
1381
  shape_members: dict,
1256
1382
  operation_model: OperationModel,
1257
1383
  mime_type: str,
@@ -1262,7 +1388,7 @@ class JSONResponseSerializer(ResponseSerializer):
1262
1388
  else:
1263
1389
  json_version = operation_model.metadata.get("jsonVersion")
1264
1390
  if json_version is not None:
1265
- response.headers["Content-Type"] = "application/x-amz-json-%s" % json_version
1391
+ response.headers["Content-Type"] = f"application/x-amz-json-{json_version}"
1266
1392
  response.set_response(
1267
1393
  self._serialize_body_params(parameters, shape, operation_model, mime_type, request_id)
1268
1394
  )
@@ -1274,7 +1400,7 @@ class JSONResponseSerializer(ResponseSerializer):
1274
1400
  operation_model: OperationModel,
1275
1401
  mime_type: str,
1276
1402
  request_id: str,
1277
- ) -> Optional[str]:
1403
+ ) -> str | None:
1278
1404
  body = {}
1279
1405
  if shape is not None:
1280
1406
  self._serialize(body, params, shape, None, mime_type)
@@ -1284,10 +1410,10 @@ class JSONResponseSerializer(ResponseSerializer):
1284
1410
  else:
1285
1411
  return json.dumps(body)
1286
1412
 
1287
- def _serialize(self, body: dict, value: Any, shape, key: Optional[str], mime_type: str):
1413
+ def _serialize(self, body: dict, value: Any, shape, key: str | None, mime_type: str):
1288
1414
  """This method dynamically invokes the correct `_serialize_type_*` method for each shape type."""
1289
1415
  try:
1290
- method = getattr(self, "_serialize_type_%s" % shape.type_name, self._default_serialize)
1416
+ method = getattr(self, f"_serialize_type_{shape.type_name}", self._default_serialize)
1291
1417
  method(body, value, shape, key, mime_type)
1292
1418
  except (TypeError, ValueError, AttributeError) as e:
1293
1419
  raise ProtocolSerializerError(
@@ -1295,7 +1421,7 @@ class JSONResponseSerializer(ResponseSerializer):
1295
1421
  ) from e
1296
1422
 
1297
1423
  def _serialize_type_structure(
1298
- self, body: dict, value: dict, shape: StructureShape, key: Optional[str], mime_type: str
1424
+ self, body: dict, value: dict, shape: StructureShape, key: str | None, mime_type: str
1299
1425
  ):
1300
1426
  if value is None:
1301
1427
  return
@@ -1369,9 +1495,7 @@ class JSONResponseSerializer(ResponseSerializer):
1369
1495
  timestamp_format = shape.serialization.get("timestampFormat")
1370
1496
  body[key] = self._convert_timestamp_to_str(value, timestamp_format)
1371
1497
 
1372
- def _serialize_type_blob(
1373
- self, body: dict, value: Union[str, bytes], _, key: str, mime_type: str
1374
- ):
1498
+ def _serialize_type_blob(self, body: dict, value: str | bytes, _, key: str, mime_type: str):
1375
1499
  if mime_type in self.CBOR_TYPES:
1376
1500
  body[key] = value
1377
1501
  else:
@@ -1380,7 +1504,7 @@ class JSONResponseSerializer(ResponseSerializer):
1380
1504
  def _prepare_additional_traits_in_response(
1381
1505
  self, response: Response, operation_model: OperationModel, request_id: str
1382
1506
  ):
1383
- response.headers["x-amzn-requestid"] = request_id
1507
+ response.headers.setdefault("x-amzn-RequestId", request_id)
1384
1508
  response = super()._prepare_additional_traits_in_response(
1385
1509
  response, operation_model, request_id
1386
1510
  )
@@ -1410,6 +1534,504 @@ class RestJSONResponseSerializer(BaseRestResponseSerializer, JSONResponseSeriali
1410
1534
  serialized.headers["Content-Type"] = mime_type
1411
1535
 
1412
1536
 
1537
+ class BaseCBORResponseSerializer(ResponseSerializer):
1538
+ """
1539
+ The ``BaseCBORResponseSerializer`` performs the basic logic for the CBOR response serialization.
1540
+
1541
+ There are two types of map/list in CBOR, indefinite length types and "defined" ones:
1542
+ You can use the `\xbf` byte marker to indicate a map with indefinite length, then `\xff` to indicate the end
1543
+ of the map.
1544
+ You can also use, for example, `\xa4` to indicate a map with exactly 4 things in it, so `\xff` is not
1545
+ required at the end.
1546
+ AWS, for both Kinesis and `smithy-rpc-v2-cbor` services, is using indefinite data structures when returning
1547
+ responses.
1548
+
1549
+ The CBOR serializer cannot serialize an exception if it is not defined in our specs.
1550
+ LocalStack defines a way to have user-defined exception by subclassing `CommonServiceException`, so it needs to be
1551
+ able to encode those, as well as InternalError
1552
+ We are creating a default botocore structure shape (`_DEFAULT_ERROR_STRUCTURE_SHAPE`) to be used in such cases.
1553
+ """
1554
+
1555
+ SUPPORTED_MIME_TYPES = [APPLICATION_CBOR, APPLICATION_AMZ_CBOR_1_1]
1556
+
1557
+ UNSIGNED_INT_MAJOR_TYPE = 0
1558
+ NEGATIVE_INT_MAJOR_TYPE = 1
1559
+ BLOB_MAJOR_TYPE = 2
1560
+ STRING_MAJOR_TYPE = 3
1561
+ LIST_MAJOR_TYPE = 4
1562
+ MAP_MAJOR_TYPE = 5
1563
+ TAG_MAJOR_TYPE = 6
1564
+ FLOAT_AND_SIMPLE_MAJOR_TYPE = 7
1565
+
1566
+ INDEFINITE_ITEM_ADDITIONAL_INFO = 31
1567
+ BREAK_CODE = b"\xff"
1568
+ USE_INDEFINITE_DATA_STRUCTURE = True
1569
+
1570
+ _ERROR_TYPE_SHAPE = StringShape(shape_name="__type", shape_model={"type": "string"})
1571
+
1572
+ _DEFAULT_ERROR_STRUCTURE_SHAPE = StructureShape(
1573
+ shape_name="DefaultErrorStructure",
1574
+ shape_model={
1575
+ "type": "structure",
1576
+ "members": {
1577
+ "message": {"shape": "ErrorMessage"},
1578
+ "__type": {"shape": "ErrorType"},
1579
+ },
1580
+ "error": {"code": "DefaultErrorStructure", "httpStatusCode": 400, "senderFault": True},
1581
+ "exception": True,
1582
+ },
1583
+ shape_resolver=ShapeResolver(
1584
+ shape_map={
1585
+ "ErrorMessage": {"type": "string"},
1586
+ "ErrorType": {"type": "string"},
1587
+ },
1588
+ ),
1589
+ )
1590
+
1591
+ def _serialize_data_item(
1592
+ self, serialized: bytearray, value: Any, shape: Shape | None, name: str | None = None
1593
+ ) -> None:
1594
+ method = getattr(self, f"_serialize_type_{shape.type_name}")
1595
+ if method is None:
1596
+ raise ValueError(
1597
+ f"Unrecognized C2J type: {shape.type_name}, unable to serialize request"
1598
+ )
1599
+ method(serialized, value, shape, name)
1600
+
1601
+ def _serialize_type_integer(
1602
+ self, serialized: bytearray, value: int, shape: Shape | None, name: str | None = None
1603
+ ) -> None:
1604
+ if value >= 0:
1605
+ major_type = self.UNSIGNED_INT_MAJOR_TYPE
1606
+ else:
1607
+ major_type = self.NEGATIVE_INT_MAJOR_TYPE
1608
+ # The only differences in serializing negative and positive integers is
1609
+ # that for negative, we set the major type to 1 and set the value to -1
1610
+ # minus the value
1611
+ value = -1 - value
1612
+ additional_info, num_bytes = self._get_additional_info_and_num_bytes(value)
1613
+ initial_byte = self._get_initial_byte(major_type, additional_info)
1614
+ if num_bytes == 0:
1615
+ serialized.extend(initial_byte)
1616
+ else:
1617
+ serialized.extend(initial_byte + value.to_bytes(num_bytes, "big"))
1618
+
1619
+ def _serialize_type_long(
1620
+ self, serialized: bytearray, value: int, shape: Shape, name: str | None = None
1621
+ ) -> None:
1622
+ self._serialize_type_integer(serialized, value, shape, name)
1623
+
1624
+ def _serialize_type_blob(
1625
+ self,
1626
+ serialized: bytearray,
1627
+ value: str | bytes | IO[bytes],
1628
+ shape: Shape | None,
1629
+ name: str | None = None,
1630
+ ) -> None:
1631
+ if isinstance(value, str):
1632
+ value = value.encode("utf-8")
1633
+ elif not isinstance(value, (bytes, bytearray)):
1634
+ # We support file-like objects for blobs; these already have been
1635
+ # validated to ensure they have a read method
1636
+ value = value.read()
1637
+ length = len(value)
1638
+ additional_info, num_bytes = self._get_additional_info_and_num_bytes(length)
1639
+ initial_byte = self._get_initial_byte(self.BLOB_MAJOR_TYPE, additional_info)
1640
+ if num_bytes == 0:
1641
+ serialized.extend(initial_byte)
1642
+ else:
1643
+ serialized.extend(initial_byte + length.to_bytes(num_bytes, "big"))
1644
+ serialized.extend(value)
1645
+
1646
+ def _serialize_type_string(
1647
+ self, serialized: bytearray, value: str, shape: Shape | None, name: str | None = None
1648
+ ) -> None:
1649
+ encoded = value.encode("utf-8")
1650
+ length = len(encoded)
1651
+ additional_info, num_bytes = self._get_additional_info_and_num_bytes(length)
1652
+ initial_byte = self._get_initial_byte(self.STRING_MAJOR_TYPE, additional_info)
1653
+ if num_bytes == 0:
1654
+ serialized.extend(initial_byte + encoded)
1655
+ else:
1656
+ serialized.extend(initial_byte + length.to_bytes(num_bytes, "big") + encoded)
1657
+
1658
+ def _serialize_type_list(
1659
+ self, serialized: bytearray, value: list, shape: Shape | None, name: str | None = None
1660
+ ) -> None:
1661
+ initial_bytes, closing_bytes = self._get_bytes_for_data_structure(
1662
+ value, self.LIST_MAJOR_TYPE
1663
+ )
1664
+ serialized.extend(initial_bytes)
1665
+
1666
+ for item in value:
1667
+ self._serialize_data_item(serialized, item, shape.member)
1668
+
1669
+ if closing_bytes is not None:
1670
+ serialized.extend(closing_bytes)
1671
+
1672
+ def _serialize_type_map(
1673
+ self, serialized: bytearray, value: dict, shape: Shape | None, name: str | None = None
1674
+ ) -> None:
1675
+ initial_bytes, closing_bytes = self._get_bytes_for_data_structure(
1676
+ value, self.MAP_MAJOR_TYPE
1677
+ )
1678
+ serialized.extend(initial_bytes)
1679
+
1680
+ for key_item, item in value.items():
1681
+ self._serialize_data_item(serialized, key_item, shape.key)
1682
+ self._serialize_data_item(serialized, item, shape.value)
1683
+
1684
+ if closing_bytes is not None:
1685
+ serialized.extend(closing_bytes)
1686
+
1687
+ def _serialize_type_structure(
1688
+ self,
1689
+ serialized: bytearray,
1690
+ value: dict,
1691
+ shape: Shape | None,
1692
+ name: str | None = None,
1693
+ shape_members: dict[str, Shape] | None = None,
1694
+ ) -> None:
1695
+ # `_serialize_type_structure` has a different signature other `_serialize_type_*` methods as it accepts
1696
+ # `shape_members`. This is because sometimes, the `StructureShape` does not have some members defined in the
1697
+ # specs, and we want to be able to pass arbitrary members to serialize undocumented members.
1698
+ # see `_serialize_error_structure` for its specific usage
1699
+
1700
+ if name is not None:
1701
+ # For nested structures, we need to serialize the key first
1702
+ self._serialize_data_item(serialized, name, shape.key_shape)
1703
+
1704
+ # Remove `None` values from the dictionary
1705
+ value = {k: v for k, v in value.items() if v is not None}
1706
+
1707
+ initial_bytes, closing_bytes = self._get_bytes_for_data_structure(
1708
+ value, self.MAP_MAJOR_TYPE
1709
+ )
1710
+ serialized.extend(initial_bytes)
1711
+ members = shape_members or shape.members
1712
+ for member_key, member_value in value.items():
1713
+ member_shape = members[member_key]
1714
+ if "name" in member_shape.serialization:
1715
+ member_key = member_shape.serialization["name"]
1716
+ if member_value is not None:
1717
+ self._serialize_type_string(serialized, member_key, None, None)
1718
+ self._serialize_data_item(serialized, member_value, member_shape)
1719
+
1720
+ if closing_bytes is not None:
1721
+ serialized.extend(closing_bytes)
1722
+
1723
+ def _serialize_type_timestamp(
1724
+ self,
1725
+ serialized: bytearray,
1726
+ value: int | str | datetime.datetime,
1727
+ shape: Shape | None,
1728
+ name: str | None = None,
1729
+ ) -> None:
1730
+ # https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#timestamp-type-serialization
1731
+ tag = 1 # Use tag 1 for unix timestamp
1732
+ initial_byte = self._get_initial_byte(self.TAG_MAJOR_TYPE, tag)
1733
+ serialized.extend(initial_byte) # Tagging the timestamp
1734
+
1735
+ # we encode the timestamp as a double, like the Go SDK
1736
+ # https://github.com/aws/aws-sdk-go-v2/blob/5d7c17325a2581afae4455c150549174ebfd9428/internal/protocoltest/smithyrpcv2cbor/serializers.go#L664-L669
1737
+ # Currently, the Botocore serializer using unsigned integers, but it does not conform to the Smithy specs:
1738
+ # > This protocol uses epoch-seconds, also known as Unix timestamps, with millisecond
1739
+ # > (1/1000th of a second) resolution.
1740
+ timestamp = float(self._convert_timestamp_to_str(value))
1741
+ initial_byte = self._get_initial_byte(self.FLOAT_AND_SIMPLE_MAJOR_TYPE, 27)
1742
+ serialized.extend(initial_byte + struct.pack(">d", timestamp))
1743
+
1744
+ def _serialize_type_float(
1745
+ self, serialized: bytearray, value: float, shape: Shape | None, name: str | None = None
1746
+ ) -> None:
1747
+ if self._is_special_number(value):
1748
+ serialized.extend(
1749
+ self._get_bytes_for_special_numbers(value)
1750
+ ) # Handle special values like NaN or Infinity
1751
+ else:
1752
+ initial_byte = self._get_initial_byte(self.FLOAT_AND_SIMPLE_MAJOR_TYPE, 26)
1753
+ serialized.extend(initial_byte + struct.pack(">f", value))
1754
+
1755
+ def _serialize_type_double(
1756
+ self, serialized: bytearray, value: float, shape: Shape | None, name: str | None = None
1757
+ ) -> None:
1758
+ if self._is_special_number(value):
1759
+ serialized.extend(
1760
+ self._get_bytes_for_special_numbers(value)
1761
+ ) # Handle special values like NaN or Infinity
1762
+ else:
1763
+ initial_byte = self._get_initial_byte(self.FLOAT_AND_SIMPLE_MAJOR_TYPE, 27)
1764
+ serialized.extend(initial_byte + struct.pack(">d", value))
1765
+
1766
+ def _serialize_type_boolean(
1767
+ self, serialized: bytearray, value: bool, shape: Shape | None, name: str | None = None
1768
+ ) -> None:
1769
+ additional_info = 21 if value else 20
1770
+ serialized.extend(self._get_initial_byte(self.FLOAT_AND_SIMPLE_MAJOR_TYPE, additional_info))
1771
+
1772
+ @staticmethod
1773
+ def _get_additional_info_and_num_bytes(value: int) -> tuple[int, int]:
1774
+ # Values under 24 can be stored in the initial byte and don't need further
1775
+ # encoding
1776
+ if value < 24:
1777
+ return value, 0
1778
+ # Values between 24 and 255 (inclusive) can be stored in 1 byte and
1779
+ # correspond to additional info 24
1780
+ elif value < 256:
1781
+ return 24, 1
1782
+ # Values up to 65535 can be stored in two bytes and correspond to additional
1783
+ # info 25
1784
+ elif value < 65536:
1785
+ return 25, 2
1786
+ # Values up to 4294967296 can be stored in four bytes and correspond to
1787
+ # additional info 26
1788
+ elif value < 4294967296:
1789
+ return 26, 4
1790
+ # The maximum number of bytes in a definite length data items is 8 which
1791
+ # to additional info 27
1792
+ else:
1793
+ return 27, 8
1794
+
1795
+ def _get_initial_byte(self, major_type: int, additional_info: int) -> bytes:
1796
+ # The highest order three bits are the major type, so we need to bitshift the
1797
+ # major type by 5
1798
+ major_type_bytes = major_type << 5
1799
+ return (major_type_bytes | additional_info).to_bytes(1, "big")
1800
+
1801
+ @staticmethod
1802
+ def _is_special_number(value: int | float) -> bool:
1803
+ return any(
1804
+ [
1805
+ value == float("inf"),
1806
+ value == float("-inf"),
1807
+ math.isnan(value),
1808
+ ]
1809
+ )
1810
+
1811
+ def _get_bytes_for_special_numbers(self, value: int | float) -> bytes:
1812
+ additional_info = 25
1813
+ initial_byte = self._get_initial_byte(self.FLOAT_AND_SIMPLE_MAJOR_TYPE, additional_info)
1814
+ if value == float("inf"):
1815
+ return initial_byte + struct.pack(">H", 0x7C00)
1816
+ elif value == float("-inf"):
1817
+ return initial_byte + struct.pack(">H", 0xFC00)
1818
+ elif math.isnan(value):
1819
+ return initial_byte + struct.pack(">H", 0x7E00)
1820
+
1821
+ def _get_bytes_for_data_structure(
1822
+ self, value: list | dict, major_type: int
1823
+ ) -> tuple[bytes, bytes | None]:
1824
+ if self.USE_INDEFINITE_DATA_STRUCTURE:
1825
+ additional_info = self.INDEFINITE_ITEM_ADDITIONAL_INFO
1826
+ return self._get_initial_byte(major_type, additional_info), self.BREAK_CODE
1827
+ else:
1828
+ length = len(value)
1829
+ additional_info, num_bytes = self._get_additional_info_and_num_bytes(length)
1830
+ initial_byte = self._get_initial_byte(major_type, additional_info)
1831
+ if num_bytes != 0:
1832
+ initial_byte = initial_byte + length.to_bytes(num_bytes, "big")
1833
+
1834
+ return initial_byte, None
1835
+
1836
+ def _serialize_error_structure(
1837
+ self, body: bytearray, shape: Shape | None, error: ServiceException, code: str
1838
+ ):
1839
+ if not shape:
1840
+ shape = self._DEFAULT_ERROR_STRUCTURE_SHAPE
1841
+ shape_members = shape.members
1842
+ else:
1843
+ # we need to manually add the `__type` field to the shape members as it is not part of the specs
1844
+ # we do a shallow copy of the shape members
1845
+ shape_members = shape.members.copy()
1846
+ shape_members["__type"] = self._ERROR_TYPE_SHAPE
1847
+
1848
+ # Error responses in the rpcv2Cbor protocol MUST be serialized identically to standard responses with one
1849
+ # additional component to distinguish which error is contained: a body field named __type.
1850
+ params = {"__type": code}
1851
+
1852
+ for member in shape_members:
1853
+ if hasattr(error, member):
1854
+ value = getattr(error, member)
1855
+
1856
+ # Default error message fields can sometimes have different casing in the specs
1857
+ elif member.lower() in ["code", "message"] and hasattr(error, member.lower()):
1858
+ value = getattr(error, member.lower())
1859
+
1860
+ else:
1861
+ continue
1862
+
1863
+ if value is None:
1864
+ # do not serialize a value that is set to `None`
1865
+ continue
1866
+
1867
+ # if the value is falsy (empty string, empty list) and not in the Shape required members, AWS will
1868
+ # not serialize it, and it will not be part of the response body.
1869
+ if value or member in shape.required_members:
1870
+ params[member] = value
1871
+
1872
+ self._serialize_type_structure(body, params, shape, None, shape_members=shape_members)
1873
+
1874
+
1875
+ class CBORResponseSerializer(BaseCBORResponseSerializer):
1876
+ """
1877
+ The ``CBORResponseSerializer`` is responsible for the serialization of responses from services with the ``cbor``
1878
+ protocol. It implements the CBOR response body serialization, which is only currently used by Kinesis and is derived
1879
+ conceptually from the ``JSONResponseSerializer``
1880
+ """
1881
+
1882
+ TIMESTAMP_FORMAT = "unixtimestamp"
1883
+
1884
+ def _serialize_error(
1885
+ self,
1886
+ error: ServiceException,
1887
+ response: Response,
1888
+ shape: StructureShape,
1889
+ operation_model: OperationModel,
1890
+ mime_type: str,
1891
+ request_id: str,
1892
+ ) -> None:
1893
+ body = bytearray()
1894
+ response.content_type = mime_type
1895
+ response.headers["X-Amzn-Errortype"] = error.code
1896
+
1897
+ self._serialize_error_structure(body, shape, error, code=error.code)
1898
+
1899
+ response.set_response(bytes(body))
1900
+
1901
+ def _serialize_response(
1902
+ self,
1903
+ parameters: dict,
1904
+ response: Response,
1905
+ shape: Shape | None,
1906
+ shape_members: dict,
1907
+ operation_model: OperationModel,
1908
+ mime_type: str,
1909
+ request_id: str,
1910
+ ) -> None:
1911
+ response.content_type = mime_type
1912
+ response.set_response(
1913
+ self._serialize_body_params(parameters, shape, operation_model, mime_type, request_id)
1914
+ )
1915
+
1916
+ def _serialize_body_params(
1917
+ self,
1918
+ params: dict,
1919
+ shape: Shape,
1920
+ operation_model: OperationModel,
1921
+ mime_type: str,
1922
+ request_id: str,
1923
+ ) -> bytes | None:
1924
+ if shape is None:
1925
+ return b""
1926
+ body = bytearray()
1927
+ self._serialize_data_item(body, params, shape)
1928
+ return bytes(body)
1929
+
1930
+ def _prepare_additional_traits_in_response(
1931
+ self, response: Response, operation_model: OperationModel, request_id: str
1932
+ ) -> Response:
1933
+ response.headers["x-amzn-RequestId"] = request_id
1934
+ response = super()._prepare_additional_traits_in_response(
1935
+ response, operation_model, request_id
1936
+ )
1937
+ return response
1938
+
1939
+
1940
+ class BaseRpcV2ResponseSerializer(ResponseSerializer):
1941
+ """
1942
+ The BaseRpcV2ResponseSerializer performs the basic logic for the RPC V2 response serialization.
1943
+ The only variance between the various RPCv2 protocols is the way the body is serialized for regular responses,
1944
+ and the way they will encode exceptions.
1945
+ """
1946
+
1947
+ def _serialize_response(
1948
+ self,
1949
+ parameters: dict,
1950
+ response: Response,
1951
+ shape: Shape | None,
1952
+ shape_members: dict,
1953
+ operation_model: OperationModel,
1954
+ mime_type: str,
1955
+ request_id: str,
1956
+ ) -> None:
1957
+ response.content_type = mime_type
1958
+ response.set_response(
1959
+ self._serialize_body_params(parameters, shape, operation_model, mime_type, request_id)
1960
+ )
1961
+
1962
+ def _serialize_body_params(
1963
+ self,
1964
+ params: dict,
1965
+ shape: Shape,
1966
+ operation_model: OperationModel,
1967
+ mime_type: str,
1968
+ request_id: str,
1969
+ ) -> bytes | None:
1970
+ raise NotImplementedError
1971
+
1972
+
1973
+ class RpcV2CBORResponseSerializer(
1974
+ QueryCompatibleProtocolMixin, BaseRpcV2ResponseSerializer, BaseCBORResponseSerializer
1975
+ ):
1976
+ """
1977
+ The RpcV2CBORResponseSerializer implements the CBOR body serialization part for the RPC v2 protocol, and implements the
1978
+ specific exception serialization.
1979
+ https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html
1980
+ """
1981
+
1982
+ # the Smithy spec defines that only `application/cbor` is supported for RPC v2 CBOR
1983
+ SUPPORTED_MIME_TYPES = [APPLICATION_CBOR]
1984
+ TIMESTAMP_FORMAT = "unixtimestamp"
1985
+
1986
+ def _serialize_body_params(
1987
+ self,
1988
+ params: dict,
1989
+ shape: Shape,
1990
+ operation_model: OperationModel,
1991
+ mime_type: str,
1992
+ request_id: str,
1993
+ ) -> bytes | None:
1994
+ if shape is None:
1995
+ return b""
1996
+ body = bytearray()
1997
+ self._serialize_data_item(body, params, shape)
1998
+ return bytes(body)
1999
+
2000
+ def _serialize_error(
2001
+ self,
2002
+ error: ServiceException,
2003
+ response: Response,
2004
+ shape: StructureShape,
2005
+ operation_model: OperationModel,
2006
+ mime_type: str,
2007
+ request_id: str,
2008
+ ) -> None:
2009
+ body = bytearray()
2010
+ response.content_type = mime_type # can only be 'application/cbor'
2011
+
2012
+ # Responses for the rpcv2Cbor protocol SHOULD NOT contain the X-Amzn-ErrorType header.
2013
+ # Type information is always serialized in the payload. This is different from the `json` protocol
2014
+ is_query_compatible = operation_model.service_model.is_query_compatible
2015
+ code = self._get_error_code(is_query_compatible, error, shape)
2016
+
2017
+ self._serialize_error_structure(body, shape, error, code=code)
2018
+
2019
+ response.set_response(bytes(body))
2020
+
2021
+ if is_query_compatible:
2022
+ self._add_query_compatible_error_header(response, error)
2023
+
2024
+ def _prepare_additional_traits_in_response(
2025
+ self, response: Response, operation_model: OperationModel, request_id: str
2026
+ ):
2027
+ response.headers["x-amzn-RequestId"] = request_id
2028
+ response.headers["Smithy-Protocol"] = "rpc-v2-cbor"
2029
+ response = super()._prepare_additional_traits_in_response(
2030
+ response, operation_model, request_id
2031
+ )
2032
+ return response
2033
+
2034
+
1413
2035
  class S3ResponseSerializer(RestXMLResponseSerializer):
1414
2036
  """
1415
2037
  The ``S3ResponseSerializer`` adds some minor logic to handle S3 specific peculiarities with the error response
@@ -1466,7 +2088,7 @@ class S3ResponseSerializer(RestXMLResponseSerializer):
1466
2088
  self,
1467
2089
  parameters: dict,
1468
2090
  response: Response,
1469
- shape: Optional[Shape],
2091
+ shape: Shape | None,
1470
2092
  shape_members: dict,
1471
2093
  operation_model: OperationModel,
1472
2094
  mime_type: str,
@@ -1528,7 +2150,7 @@ class S3ResponseSerializer(RestXMLResponseSerializer):
1528
2150
  operation_model: OperationModel,
1529
2151
  mime_type: str,
1530
2152
  request_id: str,
1531
- ) -> Optional[str]:
2153
+ ) -> str | None:
1532
2154
  root = self._serialize_body_params_to_xml(params, shape, operation_model, mime_type)
1533
2155
  # S3 does not follow the specs on the root tag name for 41 of 44 operations
1534
2156
  root.tag = self._RESPONSE_ROOT_TAGS.get(root.tag, root.tag)
@@ -1568,7 +2190,7 @@ class S3ResponseSerializer(RestXMLResponseSerializer):
1568
2190
  def _create_empty_node(xmlnode: ETree.Element, name: str) -> None:
1569
2191
  ETree.SubElement(xmlnode, name)
1570
2192
 
1571
- def _prepare_additional_traits_in_xml(self, root: Optional[ETree.Element], request_id: str):
2193
+ def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str):
1572
2194
  # some tools (Serverless) require a newline after the "<?xml ...>\n" preamble line, e.g., for LocationConstraint
1573
2195
  if root and not root.tail:
1574
2196
  root.tail = "\n"
@@ -1576,7 +2198,7 @@ class S3ResponseSerializer(RestXMLResponseSerializer):
1576
2198
  root.attrib["xmlns"] = self.XML_NAMESPACE
1577
2199
 
1578
2200
  @staticmethod
1579
- def _timestamp_iso8601(value: datetime) -> str:
2201
+ def _timestamp_iso8601(value: datetime.datetime) -> str:
1580
2202
  """
1581
2203
  This is very specific to S3, S3 returns an ISO8601 timestamp but with milliseconds always set to 000
1582
2204
  Some SDKs are very picky about the length
@@ -1639,7 +2261,7 @@ class SqsQueryResponseSerializer(QueryResponseSerializer):
1639
2261
  .replace("\r", "__marker__-r__marker__")
1640
2262
  )
1641
2263
 
1642
- def _node_to_string(self, root: Optional[ETree.ElementTree], mime_type: str) -> Optional[str]:
2264
+ def _node_to_string(self, root: ETree.ElementTree | None, mime_type: str) -> str | None:
1643
2265
  """Replaces the previously "marked" characters with their encoded value."""
1644
2266
  generated_string = super()._node_to_string(root, mime_type)
1645
2267
  if generated_string is None:
@@ -1703,26 +2325,12 @@ class SqsJsonResponseSerializer(JSONResponseSerializer):
1703
2325
  "QueueNameExists": "QueueAlreadyExists",
1704
2326
  }
1705
2327
 
1706
- def _serialize_error(
1707
- self,
1708
- error: ServiceException,
1709
- response: Response,
1710
- shape: StructureShape,
1711
- operation_model: OperationModel,
1712
- mime_type: str,
1713
- request_id: str,
1714
- ) -> None:
1715
- """
1716
- Overrides _serialize_error as SQS has a special header for query API legacy reason: 'x-amzn-query-error',
1717
- which contained the exception code as well as a Sender field.
1718
- Ex: 'x-amzn-query-error': 'InvalidParameterValue;Sender'
1719
- """
1720
- # TODO: for body["__type"] = error.code, it seems AWS differs from what we send for SQS
1721
- # AWS: "com.amazon.coral.service#InvalidParameterValueException"
1722
- # or AWS: "com.amazonaws.sqs#BatchRequestTooLong"
1723
- # LocalStack: "InvalidParameterValue"
1724
- super()._serialize_error(error, response, shape, operation_model, mime_type, request_id)
1725
- # We need to add a prefix to certain errors, as they have been deleted in the specs. These will not change
2328
+ # TODO: on body error serialization (body["__type"]),it seems AWS differs from what we send for SQS
2329
+ # AWS: "com.amazon.coral.service#InvalidParameterValueException"
2330
+ # or AWS: "com.amazonaws.sqs#BatchRequestTooLong"
2331
+ # LocalStack: "InvalidParameterValue"
2332
+
2333
+ def _add_query_compatible_error_header(self, response: Response, error: ServiceException):
1726
2334
  if error.code in self.JSON_TO_QUERY_ERROR_CODES:
1727
2335
  code = self.JSON_TO_QUERY_ERROR_CODES[error.code]
1728
2336
  elif error.code in self.QUERY_PREFIXED_ERRORS:
@@ -1730,6 +2338,7 @@ class SqsJsonResponseSerializer(JSONResponseSerializer):
1730
2338
  else:
1731
2339
  code = error.code
1732
2340
 
2341
+ # SQS exceptions all have sender fault set to False, so we hardcode it to `Sender`
1733
2342
  response.headers["x-amzn-query-error"] = f"{code};Sender"
1734
2343
 
1735
2344
 
@@ -1747,11 +2356,14 @@ def gen_amzn_requestid():
1747
2356
 
1748
2357
 
1749
2358
  @functools.cache
1750
- def create_serializer(service: ServiceModel) -> ResponseSerializer:
2359
+ def create_serializer(
2360
+ service: ServiceModel, protocol: ProtocolName | None = None
2361
+ ) -> ResponseSerializer:
1751
2362
  """
1752
2363
  Creates the right serializer for the given service model.
1753
2364
 
1754
2365
  :param service: to create the serializer for
2366
+ :param protocol: the protocol for the serializer. If not provided, fallback to the service's default protocol
1755
2367
  :return: ResponseSerializer which can handle the protocol of the service
1756
2368
  """
1757
2369
 
@@ -1771,21 +2383,26 @@ def create_serializer(service: ServiceModel) -> ResponseSerializer:
1771
2383
  "rest-json": RestJSONResponseSerializer,
1772
2384
  "rest-xml": RestXMLResponseSerializer,
1773
2385
  "ec2": EC2ResponseSerializer,
2386
+ "smithy-rpc-v2-cbor": RpcV2CBORResponseSerializer,
2387
+ # TODO: implement multi-protocol support for Kinesis, so that it can uses the `cbor` protocol and remove
2388
+ # CBOR handling from JSONResponseParser
2389
+ # this is not an "official" protocol defined from the spec, but is derived from ``json``
1774
2390
  }
2391
+ service_protocol = protocol or service.protocol
1775
2392
 
1776
2393
  # Try to select a service- and protocol-specific serializer implementation
1777
2394
  if (
1778
2395
  service.service_name in service_specific_serializers
1779
- and service.protocol in service_specific_serializers[service.service_name]
2396
+ and service_protocol in service_specific_serializers[service.service_name]
1780
2397
  ):
1781
- return service_specific_serializers[service.service_name][service.protocol]()
2398
+ return service_specific_serializers[service.service_name][service_protocol]()
1782
2399
  else:
1783
2400
  # Otherwise, pick the protocol-specific serializer for the protocol of the service
1784
- return protocol_specific_serializers[service.protocol]()
2401
+ return protocol_specific_serializers[service_protocol]()
1785
2402
 
1786
2403
 
1787
2404
  def aws_response_serializer(
1788
- service_name: str, operation: str, protocol: Optional[ProtocolName] = None
2405
+ service_name: str, operation: str, protocol: ProtocolName | None = None
1789
2406
  ):
1790
2407
  """
1791
2408
  A decorator for an HTTP route that can serialize return values or exceptions into AWS responses.
@@ -1812,7 +2429,7 @@ def aws_response_serializer(
1812
2429
  def _decorate(fn):
1813
2430
  service_model = load_service(service_name, protocol=protocol)
1814
2431
  operation_model = service_model.operation_model(operation)
1815
- serializer = create_serializer(service_model)
2432
+ serializer = create_serializer(service_model, protocol=protocol)
1816
2433
 
1817
2434
  def _proxy(*args, **kwargs) -> WerkzeugResponse:
1818
2435
  # extract request from function invocation (decorator can be used for methods as well as for functions).