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.
- localstack/aws/api/apigateway/__init__.py +87 -110
- localstack/aws/api/cloudformation/__init__.py +18 -4
- localstack/aws/api/cloudwatch/__init__.py +41 -1
- localstack/aws/api/config/__init__.py +4 -0
- localstack/aws/api/core.py +8 -5
- localstack/aws/api/dynamodb/__init__.py +30 -0
- localstack/aws/api/ec2/__init__.py +1545 -66
- localstack/aws/api/events/__init__.py +12 -16
- localstack/aws/api/iam/__init__.py +7 -0
- localstack/aws/api/kinesis/__init__.py +19 -0
- localstack/aws/api/kms/__init__.py +6 -0
- localstack/aws/api/lambda_/__init__.py +36 -23
- localstack/aws/api/logs/__init__.py +20 -8
- localstack/aws/api/opensearch/__init__.py +16 -0
- localstack/aws/api/pipes/__init__.py +24 -32
- localstack/aws/api/redshift/__init__.py +9 -3
- localstack/aws/api/route53/__init__.py +5 -0
- localstack/aws/api/s3/__init__.py +12 -0
- localstack/aws/api/s3control/__init__.py +56 -0
- localstack/aws/api/scheduler/__init__.py +14 -16
- localstack/aws/api/ssm/__init__.py +2 -0
- localstack/aws/api/stepfunctions/__init__.py +88 -114
- localstack/aws/api/support/__init__.py +8 -9
- localstack/aws/api/transcribe/__init__.py +17 -0
- localstack/aws/chain.py +2 -2
- localstack/aws/client.py +14 -11
- localstack/aws/connect.py +42 -41
- localstack/aws/forwarder.py +57 -9
- localstack/aws/gateway.py +1 -3
- localstack/aws/handlers/analytics.py +2 -3
- localstack/aws/handlers/cors.py +4 -5
- localstack/aws/handlers/internal_requests.py +6 -1
- localstack/aws/handlers/logging.py +13 -4
- localstack/aws/handlers/metric_handler.py +44 -5
- localstack/aws/handlers/service.py +48 -28
- localstack/aws/mocking.py +18 -27
- localstack/aws/patches.py +2 -2
- localstack/aws/protocol/op_router.py +11 -10
- localstack/aws/protocol/parser.py +475 -49
- localstack/aws/protocol/serializer.py +723 -106
- localstack/aws/protocol/service_router.py +133 -33
- localstack/aws/protocol/validate.py +6 -6
- localstack/aws/scaffold.py +9 -10
- localstack/aws/serving/edge.py +5 -6
- localstack/aws/serving/hypercorn.py +2 -2
- localstack/aws/serving/twisted.py +1 -2
- localstack/aws/serving/werkzeug.py +2 -2
- localstack/aws/skeleton.py +12 -11
- localstack/aws/spec-patches.json +58 -0
- localstack/aws/spec.py +66 -46
- localstack/cli/exceptions.py +1 -1
- localstack/cli/localstack.py +11 -11
- localstack/cli/lpm.py +4 -5
- localstack/cli/plugins.py +1 -1
- localstack/cli/profiles.py +1 -2
- localstack/config.py +44 -30
- localstack/constants.py +4 -29
- localstack/deprecations.py +5 -5
- localstack/dev/kubernetes/__main__.py +130 -7
- localstack/dev/run/__main__.py +5 -5
- localstack/dev/run/configurators.py +1 -4
- localstack/dev/run/paths.py +6 -6
- localstack/dns/models.py +2 -1
- localstack/dns/plugins.py +5 -1
- localstack/dns/server.py +16 -6
- localstack/http/dispatcher.py +1 -2
- localstack/http/response.py +2 -2
- localstack/http/router.py +1 -1
- localstack/http/trace.py +2 -1
- localstack/logging/format.py +6 -6
- localstack/packages/api.py +13 -12
- localstack/packages/core.py +4 -4
- localstack/packages/debugpy.py +1 -3
- localstack/packages/ffmpeg.py +1 -2
- localstack/packages/java.py +38 -12
- localstack/packages/plugins.py +0 -8
- localstack/runtime/analytics.py +3 -0
- localstack/runtime/hooks.py +1 -1
- localstack/runtime/init.py +8 -9
- localstack/runtime/main.py +5 -5
- localstack/runtime/patches.py +2 -2
- localstack/runtime/shutdown.py +2 -1
- localstack/services/apigateway/exporter.py +1 -2
- localstack/services/apigateway/helpers.py +7 -10
- localstack/services/apigateway/legacy/context.py +21 -21
- localstack/services/apigateway/legacy/helpers.py +27 -28
- localstack/services/apigateway/legacy/integration.py +11 -10
- localstack/services/apigateway/legacy/invocations.py +6 -5
- localstack/services/apigateway/legacy/provider.py +148 -68
- localstack/services/apigateway/legacy/router_asf.py +2 -2
- localstack/services/apigateway/legacy/templates.py +6 -6
- localstack/services/apigateway/models.py +16 -16
- localstack/services/apigateway/next_gen/execute_api/api.py +2 -2
- localstack/services/apigateway/next_gen/execute_api/context.py +25 -25
- localstack/services/apigateway/next_gen/execute_api/handlers/api_key_validation.py +2 -5
- localstack/services/apigateway/next_gen/execute_api/handlers/method_request.py +7 -2
- localstack/services/apigateway/next_gen/execute_api/handlers/parse.py +1 -2
- localstack/services/apigateway/next_gen/execute_api/handlers/resource_router.py +2 -3
- localstack/services/apigateway/next_gen/execute_api/header_utils.py +1 -1
- localstack/services/apigateway/next_gen/execute_api/helpers.py +2 -2
- localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +9 -6
- localstack/services/apigateway/next_gen/execute_api/integrations/http.py +12 -12
- localstack/services/apigateway/next_gen/execute_api/router.py +31 -0
- localstack/services/apigateway/next_gen/execute_api/template_mapping.py +2 -2
- localstack/services/apigateway/next_gen/execute_api/test_invoke.py +114 -9
- localstack/services/apigateway/next_gen/execute_api/variables.py +63 -63
- localstack/services/apigateway/next_gen/provider.py +5 -0
- localstack/services/apigateway/resource_providers/aws_apigateway_account.py +3 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_account_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_apikey.py +14 -14
- localstack/services/apigateway/resource_providers/aws_apigateway_apikey_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py +5 -5
- localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_deployment.py +46 -46
- localstack/services/apigateway/resource_providers/aws_apigateway_deployment_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_domainname.py +18 -18
- localstack/services/apigateway/resource_providers/aws_apigateway_domainname_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse.py +7 -7
- localstack/services/apigateway/resource_providers/aws_apigateway_gatewayresponse_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_method.py +36 -36
- localstack/services/apigateway/resource_providers/aws_apigateway_method_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_model.py +6 -6
- localstack/services/apigateway/resource_providers/aws_apigateway_model_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator.py +6 -6
- localstack/services/apigateway/resource_providers/aws_apigateway_requestvalidator_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_resource.py +6 -6
- localstack/services/apigateway/resource_providers/aws_apigateway_resource_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_restapi.py +26 -26
- localstack/services/apigateway/resource_providers/aws_apigateway_restapi_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_stage.py +33 -33
- localstack/services/apigateway/resource_providers/aws_apigateway_stage_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_usageplan.py +18 -18
- localstack/services/apigateway/resource_providers/aws_apigateway_usageplan_plugin.py +1 -3
- localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey.py +5 -5
- localstack/services/apigateway/resource_providers/aws_apigateway_usageplankey_plugin.py +1 -3
- localstack/services/cdk/resource_providers/cdk_metadata.py +4 -3
- localstack/services/cdk/resource_providers/cdk_metadata_plugin.py +1 -3
- localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate.py +14 -14
- localstack/services/certificatemanager/resource_providers/aws_certificatemanager_certificate_plugin.py +1 -3
- localstack/services/cloudformation/api_utils.py +4 -8
- localstack/services/cloudformation/cfn_utils.py +2 -2
- localstack/services/cloudformation/deployment_utils.py +14 -12
- localstack/services/cloudformation/engine/changes.py +3 -3
- localstack/services/cloudformation/engine/entities.py +27 -17
- localstack/services/cloudformation/engine/parameters.py +4 -4
- localstack/services/cloudformation/engine/template_deployer.py +15 -14
- localstack/services/cloudformation/engine/template_utils.py +34 -12
- localstack/services/cloudformation/engine/transformers.py +11 -8
- localstack/services/cloudformation/engine/types.py +5 -4
- localstack/services/cloudformation/engine/v2/change_set_model.py +336 -39
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +96 -17
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +289 -136
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +315 -146
- localstack/services/cloudformation/engine/v2/change_set_model_transform.py +380 -105
- localstack/services/cloudformation/engine/v2/change_set_model_validator.py +183 -0
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +6 -0
- localstack/services/cloudformation/engine/v2/resolving.py +102 -0
- localstack/services/cloudformation/engine/yaml_parser.py +9 -2
- localstack/services/cloudformation/provider.py +11 -6
- localstack/services/cloudformation/provider_utils.py +34 -4
- localstack/services/cloudformation/resource_provider.py +31 -21
- localstack/services/cloudformation/resource_providers/aws_cloudformation_macro.py +7 -7
- localstack/services/cloudformation/resource_providers/aws_cloudformation_macro_plugin.py +1 -3
- localstack/services/cloudformation/resource_providers/aws_cloudformation_stack.py +9 -9
- localstack/services/cloudformation/resource_providers/aws_cloudformation_stack_plugin.py +1 -3
- localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition.py +6 -6
- localstack/services/cloudformation/resource_providers/aws_cloudformation_waitcondition_plugin.py +1 -3
- localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle.py +2 -2
- localstack/services/cloudformation/resource_providers/aws_cloudformation_waitconditionhandle_plugin.py +1 -3
- localstack/services/cloudformation/resources.py +24149 -0
- localstack/services/cloudformation/scaffolding/__main__.py +13 -12
- localstack/services/cloudformation/scaffolding/propgen.py +2 -2
- localstack/services/cloudformation/service_models.py +2 -2
- localstack/services/cloudformation/stores.py +33 -22
- localstack/services/cloudformation/v2/entities.py +103 -88
- localstack/services/cloudformation/v2/provider.py +872 -131
- localstack/services/cloudformation/v2/types.py +38 -0
- localstack/services/cloudformation/v2/utils.py +4 -1
- localstack/services/cloudwatch/alarm_scheduler.py +11 -8
- localstack/services/cloudwatch/cloudwatch_database_helper.py +4 -5
- localstack/services/cloudwatch/models.py +5 -7
- localstack/services/cloudwatch/provider.py +30 -25
- localstack/services/cloudwatch/provider_v2.py +27 -32
- localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm.py +40 -40
- localstack/services/cloudwatch/resource_providers/aws_cloudwatch_alarm_plugin.py +1 -3
- localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm.py +12 -12
- localstack/services/cloudwatch/resource_providers/aws_cloudwatch_compositealarm_plugin.py +1 -3
- localstack/services/dynamodb/packages.py +3 -3
- localstack/services/dynamodb/provider.py +159 -18
- localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable.py +63 -63
- localstack/services/dynamodb/resource_providers/aws_dynamodb_globaltable_plugin.py +1 -3
- localstack/services/dynamodb/resource_providers/aws_dynamodb_table.py +57 -57
- localstack/services/dynamodb/resource_providers/aws_dynamodb_table_plugin.py +1 -3
- localstack/services/dynamodb/server.py +2 -2
- localstack/services/dynamodb/utils.py +13 -14
- localstack/services/dynamodb/v2/provider.py +157 -18
- localstack/services/dynamodbstreams/dynamodbstreams_api.py +2 -2
- localstack/services/dynamodbstreams/models.py +1 -3
- localstack/services/ec2/patches.py +26 -5
- localstack/services/ec2/provider.py +3 -3
- localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions.py +10 -10
- localstack/services/ec2/resource_providers/aws_ec2_dhcpoptions_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_instance.py +96 -96
- localstack/services/ec2/resource_providers/aws_ec2_instance_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_internetgateway.py +5 -5
- localstack/services/ec2/resource_providers/aws_ec2_internetgateway_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_keypair.py +10 -10
- localstack/services/ec2/resource_providers/aws_ec2_keypair_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_natgateway.py +13 -13
- localstack/services/ec2/resource_providers/aws_ec2_natgateway_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_networkacl.py +6 -6
- localstack/services/ec2/resource_providers/aws_ec2_networkacl_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_prefixlist.py +14 -14
- localstack/services/ec2/resource_providers/aws_ec2_prefixlist_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_route.py +15 -15
- localstack/services/ec2/resource_providers/aws_ec2_route_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_routetable.py +6 -6
- localstack/services/ec2/resource_providers/aws_ec2_routetable_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_securitygroup.py +29 -29
- localstack/services/ec2/resource_providers/aws_ec2_securitygroup_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_subnet.py +19 -19
- localstack/services/ec2/resource_providers/aws_ec2_subnet_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation.py +4 -4
- localstack/services/ec2/resource_providers/aws_ec2_subnetroutetableassociation_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_transitgateway.py +16 -16
- localstack/services/ec2/resource_providers/aws_ec2_transitgateway_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment.py +9 -9
- localstack/services/ec2/resource_providers/aws_ec2_transitgatewayattachment_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_vpc.py +15 -15
- localstack/services/ec2/resource_providers/aws_ec2_vpc_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint.py +29 -22
- localstack/services/ec2/resource_providers/aws_ec2_vpcendpoint_plugin.py +1 -3
- localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment.py +5 -5
- localstack/services/ec2/resource_providers/aws_ec2_vpcgatewayattachment_plugin.py +1 -3
- localstack/services/ecr/resource_providers/aws_ecr_repository.py +22 -19
- localstack/services/ecr/resource_providers/aws_ecr_repository_plugin.py +1 -3
- localstack/services/edge.py +6 -6
- localstack/services/es/provider.py +21 -21
- localstack/services/events/archive.py +2 -2
- localstack/services/events/connection.py +5 -5
- localstack/services/events/event_bus.py +9 -9
- localstack/services/events/event_rule_engine.py +31 -13
- localstack/services/events/models.py +29 -30
- localstack/services/events/provider.py +29 -26
- localstack/services/events/replay.py +3 -3
- localstack/services/events/resource_providers/aws_events_apidestination.py +8 -8
- localstack/services/events/resource_providers/aws_events_apidestination_plugin.py +1 -3
- localstack/services/events/resource_providers/aws_events_connection.py +27 -27
- localstack/services/events/resource_providers/aws_events_connection_plugin.py +1 -3
- localstack/services/events/resource_providers/aws_events_eventbus.py +9 -9
- localstack/services/events/resource_providers/aws_events_eventbus_plugin.py +1 -3
- localstack/services/events/resource_providers/aws_events_eventbuspolicy.py +11 -11
- localstack/services/events/resource_providers/aws_events_eventbuspolicy_plugin.py +1 -3
- localstack/services/events/resource_providers/aws_events_rule.py +82 -82
- localstack/services/events/resource_providers/aws_events_rule_plugin.py +1 -3
- localstack/services/events/rule.py +15 -15
- localstack/services/events/target.py +21 -13
- localstack/services/events/utils.py +7 -7
- localstack/services/events/v1/models.py +1 -3
- localstack/services/events/v1/provider.py +15 -15
- localstack/services/firehose/models.py +1 -3
- localstack/services/firehose/provider.py +25 -16
- localstack/services/iam/iam_patches.py +5 -6
- localstack/services/iam/provider.py +14 -119
- localstack/services/iam/resource_providers/aws_iam_accesskey.py +6 -6
- localstack/services/iam/resource_providers/aws_iam_accesskey_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_group.py +9 -9
- localstack/services/iam/resource_providers/aws_iam_group_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_instanceprofile.py +5 -5
- localstack/services/iam/resource_providers/aws_iam_instanceprofile_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_managedpolicy.py +9 -9
- localstack/services/iam/resource_providers/aws_iam_managedpolicy_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_policy.py +7 -7
- localstack/services/iam/resource_providers/aws_iam_policy_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_role.py +16 -16
- localstack/services/iam/resource_providers/aws_iam_role_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_servercertificate.py +10 -10
- localstack/services/iam/resource_providers/aws_iam_servercertificate_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_servicelinkedrole.py +5 -5
- localstack/services/iam/resource_providers/aws_iam_servicelinkedrole_plugin.py +1 -3
- localstack/services/iam/resource_providers/aws_iam_user.py +17 -17
- localstack/services/iam/resource_providers/aws_iam_user_plugin.py +1 -3
- localstack/services/iam/resources/policy_simulator.py +133 -0
- localstack/services/kinesis/kinesis_mock_server.py +7 -8
- localstack/services/kinesis/models.py +17 -5
- localstack/services/kinesis/packages.py +3 -3
- localstack/services/kinesis/provider.py +86 -3
- localstack/services/kinesis/resource_providers/aws_kinesis_stream.py +13 -13
- localstack/services/kinesis/resource_providers/aws_kinesis_stream_plugin.py +1 -3
- localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer.py +7 -7
- localstack/services/kinesis/resource_providers/aws_kinesis_streamconsumer_plugin.py +1 -3
- localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream.py +191 -191
- localstack/services/kinesisfirehose/resource_providers/aws_kinesisfirehose_deliverystream_plugin.py +1 -3
- localstack/services/kms/models.py +21 -18
- localstack/services/kms/provider.py +62 -26
- localstack/services/kms/resource_providers/aws_kms_alias.py +3 -3
- localstack/services/kms/resource_providers/aws_kms_alias_plugin.py +1 -3
- localstack/services/kms/resource_providers/aws_kms_key.py +14 -14
- localstack/services/kms/resource_providers/aws_kms_key_plugin.py +1 -3
- localstack/services/kms/utils.py +4 -3
- localstack/services/lambda_/api_utils.py +19 -16
- localstack/services/lambda_/custom_endpoints.py +2 -2
- localstack/services/lambda_/event_source_mapping/esm_worker_factory.py +4 -7
- localstack/services/lambda_/event_source_mapping/pipe_utils.py +2 -2
- localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +1 -1
- localstack/services/lambda_/event_source_mapping/senders/sender_utils.py +2 -1
- localstack/services/lambda_/hooks.py +6 -1
- localstack/services/lambda_/invocation/assignment.py +1 -2
- localstack/services/lambda_/invocation/docker_runtime_executor.py +7 -11
- localstack/services/lambda_/invocation/event_manager.py +1 -1
- localstack/services/lambda_/invocation/execution_environment.py +4 -4
- localstack/services/lambda_/invocation/executor_endpoint.py +8 -11
- localstack/services/lambda_/invocation/internal_sqs_queue.py +6 -10
- localstack/services/lambda_/invocation/lambda_models.py +33 -30
- localstack/services/lambda_/invocation/lambda_service.py +12 -5
- localstack/services/lambda_/invocation/logs.py +2 -3
- localstack/services/lambda_/invocation/runtime_executor.py +3 -3
- localstack/services/lambda_/invocation/version_manager.py +31 -8
- localstack/services/lambda_/ldm.py +14 -0
- localstack/services/lambda_/packages.py +3 -4
- localstack/services/lambda_/provider.py +9 -26
- localstack/services/lambda_/provider_utils.py +1 -1
- localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig.py +8 -8
- localstack/services/lambda_/resource_providers/aws_lambda_codesigningconfig_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig.py +11 -11
- localstack/services/lambda_/resource_providers/aws_lambda_eventinvokeconfig_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping.py +39 -39
- localstack/services/lambda_/resource_providers/aws_lambda_eventsourcemapping_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_function.py +54 -54
- localstack/services/lambda_/resource_providers/aws_lambda_function_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_layerversion.py +11 -11
- localstack/services/lambda_/resource_providers/aws_lambda_layerversion_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission.py +6 -6
- localstack/services/lambda_/resource_providers/aws_lambda_layerversionpermission_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_permission.py +10 -10
- localstack/services/lambda_/resource_providers/aws_lambda_permission_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_url.py +15 -15
- localstack/services/lambda_/resource_providers/aws_lambda_url_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/aws_lambda_version.py +8 -8
- localstack/services/lambda_/resource_providers/aws_lambda_version_plugin.py +1 -3
- localstack/services/lambda_/resource_providers/lambda_alias.py +12 -12
- localstack/services/lambda_/resource_providers/lambda_alias_plugin.py +1 -3
- localstack/services/lambda_/runtimes.py +1 -3
- localstack/services/lambda_/urlrouter.py +14 -1
- localstack/services/logs/models.py +1 -3
- localstack/services/logs/provider.py +39 -22
- localstack/services/logs/resource_providers/aws_logs_loggroup.py +9 -9
- localstack/services/logs/resource_providers/aws_logs_loggroup_plugin.py +1 -3
- localstack/services/logs/resource_providers/aws_logs_logstream.py +4 -4
- localstack/services/logs/resource_providers/aws_logs_logstream_plugin.py +1 -3
- localstack/services/logs/resource_providers/aws_logs_subscriptionfilter.py +7 -7
- localstack/services/logs/resource_providers/aws_logs_subscriptionfilter_plugin.py +1 -3
- localstack/services/moto.py +5 -4
- localstack/services/opensearch/cluster.py +28 -20
- localstack/services/opensearch/cluster_manager.py +13 -14
- localstack/services/opensearch/models.py +1 -3
- localstack/services/opensearch/packages.py +27 -9
- localstack/services/opensearch/provider.py +15 -10
- localstack/services/opensearch/resource_providers/aws_elasticsearch_domain.py +61 -61
- localstack/services/opensearch/resource_providers/aws_elasticsearch_domain_plugin.py +1 -3
- localstack/services/opensearch/resource_providers/aws_opensearchservice_domain.py +89 -89
- localstack/services/opensearch/resource_providers/aws_opensearchservice_domain_plugin.py +1 -3
- localstack/services/opensearch/versions.py +57 -10
- localstack/services/plugins.py +37 -32
- localstack/services/providers.py +10 -2
- localstack/services/redshift/provider.py +0 -21
- localstack/services/redshift/resource_providers/aws_redshift_cluster.py +57 -57
- localstack/services/redshift/resource_providers/aws_redshift_cluster_plugin.py +1 -3
- localstack/services/resource_groups/resource_providers/aws_resourcegroups_group.py +21 -21
- localstack/services/resource_groups/resource_providers/aws_resourcegroups_group_plugin.py +1 -3
- localstack/services/route53/models.py +1 -3
- localstack/services/route53/provider.py +1 -2
- localstack/services/route53/resource_providers/aws_route53_healthcheck.py +6 -6
- localstack/services/route53/resource_providers/aws_route53_healthcheck_plugin.py +1 -3
- localstack/services/route53/resource_providers/aws_route53_recordset.py +27 -27
- localstack/services/route53/resource_providers/aws_route53_recordset_plugin.py +1 -3
- localstack/services/route53resolver/models.py +8 -10
- localstack/services/route53resolver/provider.py +12 -12
- localstack/services/s3/codec.py +2 -2
- localstack/services/s3/constants.py +5 -2
- localstack/services/s3/cors.py +8 -8
- localstack/services/s3/models.py +73 -73
- localstack/services/s3/notifications.py +74 -58
- localstack/services/s3/presigned_url.py +41 -59
- localstack/services/s3/provider.py +86 -29
- localstack/services/s3/resource_providers/aws_s3_bucket.py +180 -180
- localstack/services/s3/resource_providers/aws_s3_bucket_plugin.py +1 -3
- localstack/services/s3/resource_providers/aws_s3_bucketpolicy.py +4 -4
- localstack/services/s3/resource_providers/aws_s3_bucketpolicy_plugin.py +1 -3
- localstack/services/s3/storage/core.py +4 -3
- localstack/services/s3/storage/ephemeral.py +7 -6
- localstack/services/s3/utils.py +51 -31
- localstack/services/s3/validation.py +47 -33
- localstack/services/s3/website_hosting.py +9 -7
- localstack/services/scheduler/resource_providers/aws_scheduler_schedule.py +60 -60
- localstack/services/scheduler/resource_providers/aws_scheduler_schedule_plugin.py +1 -3
- localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup.py +9 -9
- localstack/services/scheduler/resource_providers/aws_scheduler_schedulegroup_plugin.py +1 -3
- localstack/services/secretsmanager/provider.py +10 -12
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy.py +5 -5
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_resourcepolicy_plugin.py +1 -3
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule.py +21 -21
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_rotationschedule_plugin.py +1 -3
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret.py +23 -23
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secret_plugin.py +1 -3
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment.py +5 -5
- localstack/services/secretsmanager/resource_providers/aws_secretsmanager_secrettargetattachment_plugin.py +1 -3
- localstack/services/ses/models.py +8 -1
- localstack/services/ses/provider.py +128 -55
- localstack/services/ses/resource_providers/aws_ses_emailidentity.py +21 -21
- localstack/services/ses/resource_providers/aws_ses_emailidentity_plugin.py +1 -3
- localstack/services/sns/constants.py +7 -1
- localstack/services/sns/executor.py +9 -2
- localstack/services/sns/models.py +25 -25
- localstack/services/sns/provider.py +9 -7
- localstack/services/sns/publisher.py +37 -23
- localstack/services/sns/resource_providers/aws_sns_subscription.py +13 -13
- localstack/services/sns/resource_providers/aws_sns_subscription_plugin.py +1 -3
- localstack/services/sns/resource_providers/aws_sns_topic.py +16 -16
- localstack/services/sns/resource_providers/aws_sns_topic_plugin.py +1 -3
- localstack/services/sns/resource_providers/aws_sns_topicpolicy.py +4 -4
- localstack/services/sns/resource_providers/aws_sns_topicpolicy_plugin.py +1 -3
- localstack/services/sns/v2/models.py +167 -0
- localstack/services/sns/v2/provider.py +867 -0
- localstack/services/sns/v2/utils.py +130 -0
- localstack/services/sqs/constants.py +2 -2
- localstack/services/sqs/developer_api.py +205 -0
- localstack/services/sqs/models.py +71 -36
- localstack/services/sqs/provider.py +56 -332
- localstack/services/sqs/query_api.py +8 -5
- localstack/services/sqs/resource_providers/aws_sqs_queue.py +21 -21
- localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py +1 -3
- localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py +7 -5
- localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py +1 -3
- localstack/services/sqs/utils.py +123 -4
- localstack/services/ssm/provider.py +3 -4
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow.py +15 -15
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindow_plugin.py +1 -3
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget.py +10 -10
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtarget_plugin.py +1 -3
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask.py +48 -48
- localstack/services/ssm/resource_providers/aws_ssm_maintenancewindowtask_plugin.py +1 -3
- localstack/services/ssm/resource_providers/aws_ssm_parameter.py +10 -10
- localstack/services/ssm/resource_providers/aws_ssm_parameter_plugin.py +1 -3
- localstack/services/ssm/resource_providers/aws_ssm_patchbaseline.py +29 -29
- localstack/services/ssm/resource_providers/aws_ssm_patchbaseline_plugin.py +1 -3
- localstack/services/stepfunctions/asl/antlt4utils/antlr4utils.py +3 -4
- localstack/services/stepfunctions/asl/component/common/assign/assign_decl.py +1 -1
- localstack/services/stepfunctions/asl/component/common/assign/assign_decl_binding.py +1 -1
- localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_array.py +1 -1
- localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_object.py +1 -1
- localstack/services/stepfunctions/asl/component/common/catch/catcher_decl.py +9 -9
- localstack/services/stepfunctions/asl/component/common/error_name/custom_error_name.py +2 -2
- localstack/services/stepfunctions/asl/component/common/error_name/error_name.py +4 -4
- localstack/services/stepfunctions/asl/component/common/error_name/failure_event.py +8 -8
- localstack/services/stepfunctions/asl/component/common/error_name/states_error_name_type.py +1 -1
- localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_binding.py +2 -2
- localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_array.py +1 -1
- localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_object.py +1 -1
- localstack/services/stepfunctions/asl/component/common/path/input_path.py +4 -4
- localstack/services/stepfunctions/asl/component/common/path/output_path.py +4 -4
- localstack/services/stepfunctions/asl/component/common/path/result_path.py +3 -3
- localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py +1 -1
- localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py +3 -3
- localstack/services/stepfunctions/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py +1 -1
- localstack/services/stepfunctions/asl/component/common/retry/retrier_decl.py +8 -8
- localstack/services/stepfunctions/asl/component/common/string/string_expression.py +3 -3
- localstack/services/stepfunctions/asl/component/common/timeouts/timeout.py +3 -3
- localstack/services/stepfunctions/asl/component/eval_component.py +2 -3
- localstack/services/stepfunctions/asl/component/intrinsic/argument/argument.py +4 -4
- localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/array/array_partition.py +1 -1
- localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/generic/string_format.py +1 -1
- localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_array.py +1 -1
- localstack/services/stepfunctions/asl/component/intrinsic/function/statesfunction/states_function_format.py +1 -1
- localstack/services/stepfunctions/asl/component/intrinsic/jsonata.py +3 -3
- localstack/services/stepfunctions/asl/component/intrinsic/member.py +1 -1
- localstack/services/stepfunctions/asl/component/program/program.py +9 -9
- localstack/services/stepfunctions/asl/component/program/states.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state.py +10 -11
- localstack/services/stepfunctions/asl/component/state/state_choice/choice_rule.py +11 -11
- localstack/services/stepfunctions/asl/component/state/state_choice/comparison/comparison.py +5 -11
- localstack/services/stepfunctions/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +3 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +9 -9
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py +7 -7
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py +5 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py +2 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py +8 -8
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py +7 -7
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py +4 -4
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py +5 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py +10 -10
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_component.py +3 -3
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py +3 -3
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iteration_worker.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/distributed_iterator_worker.py +3 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator.py +1 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/iterator/inline_iterator_worker.py +5 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/iteration/job.py +9 -9
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/result_writer/resource_eval/resource_eval_s3.py +2 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +12 -13
- localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branch_worker.py +3 -3
- localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/branches_decl.py +7 -7
- localstack/services/stepfunctions/asl/component/state/state_execution/state_parallel/state_parallel.py +2 -3
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +7 -7
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/resource.py +3 -3
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +10 -10
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py +18 -18
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_batch.py +8 -7
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +18 -17
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_ecs.py +5 -4
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_events.py +4 -4
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_glue.py +7 -6
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py +4 -4
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py +9 -8
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sns.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py +4 -4
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task.py +5 -5
- localstack/services/stepfunctions/asl/component/state/state_execution/state_task/state_task_lambda.py +2 -2
- localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +3 -5
- localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +5 -7
- localstack/services/stepfunctions/asl/component/state/state_succeed/state_succeed.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_wait/state_wait.py +1 -1
- localstack/services/stepfunctions/asl/component/state/state_wait/wait_function/timestamp.py +2 -2
- localstack/services/stepfunctions/asl/eval/callback/callback.py +18 -18
- localstack/services/stepfunctions/asl/eval/environment.py +22 -24
- localstack/services/stepfunctions/asl/eval/evaluation_details.py +3 -5
- localstack/services/stepfunctions/asl/eval/event/event_manager.py +10 -10
- localstack/services/stepfunctions/asl/eval/event/logging.py +3 -3
- localstack/services/stepfunctions/asl/eval/program_state.py +8 -8
- localstack/services/stepfunctions/asl/eval/states.py +12 -12
- localstack/services/stepfunctions/asl/eval/test_state/environment.py +3 -5
- localstack/services/stepfunctions/asl/eval/variable_store.py +6 -6
- localstack/services/stepfunctions/asl/jsonata/jsonata.py +7 -6
- localstack/services/stepfunctions/asl/parse/asl_parser.py +1 -1
- localstack/services/stepfunctions/asl/parse/intrinsic/preprocessor.py +2 -3
- localstack/services/stepfunctions/asl/parse/preprocessor.py +44 -44
- localstack/services/stepfunctions/asl/parse/typed_props.py +2 -2
- localstack/services/stepfunctions/asl/static_analyser/intrinsic/variable_names_intrinsic_static_analyser.py +1 -1
- localstack/services/stepfunctions/asl/static_analyser/variable_references_static_analyser.py +2 -2
- localstack/services/stepfunctions/asl/utils/encoding.py +2 -2
- localstack/services/stepfunctions/asl/utils/json_path.py +2 -2
- localstack/services/stepfunctions/backend/activity.py +4 -4
- localstack/services/stepfunctions/backend/alias.py +8 -8
- localstack/services/stepfunctions/backend/execution.py +29 -30
- localstack/services/stepfunctions/backend/execution_worker.py +7 -7
- localstack/services/stepfunctions/backend/state_machine.py +28 -28
- localstack/services/stepfunctions/backend/test_state/execution.py +3 -4
- localstack/services/stepfunctions/backend/test_state/execution_worker.py +1 -3
- localstack/services/stepfunctions/mocking/mock_config.py +9 -9
- localstack/services/stepfunctions/mocking/mock_config_file.py +10 -10
- localstack/services/stepfunctions/packages.py +14 -5
- localstack/services/stepfunctions/provider.py +34 -44
- localstack/services/stepfunctions/quotas.py +2 -3
- localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity.py +6 -6
- localstack/services/stepfunctions/resource_providers/aws_stepfunctions_activity_plugin.py +1 -3
- localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine.py +25 -25
- localstack/services/stepfunctions/resource_providers/aws_stepfunctions_statemachine_plugin.py +1 -3
- localstack/services/stepfunctions/stepfunctions_utils.py +1 -2
- localstack/services/stores.py +8 -8
- localstack/services/transcribe/packages.py +1 -3
- localstack/services/transcribe/provider.py +8 -3
- localstack/state/codecs.py +61 -0
- localstack/state/core.py +11 -5
- localstack/state/inspect.py +4 -4
- localstack/state/pickle.py +36 -23
- localstack/testing/aws/asf_utils.py +3 -2
- localstack/testing/aws/cloudformation_utils.py +1 -1
- localstack/testing/aws/lambda_utils.py +15 -14
- localstack/testing/aws/util.py +3 -2
- localstack/testing/pytest/cloudformation/fixtures.py +68 -18
- localstack/testing/pytest/container.py +5 -5
- localstack/testing/pytest/filters.py +1 -3
- localstack/testing/pytest/fixtures.py +188 -49
- localstack/testing/pytest/in_memory_localstack.py +1 -3
- localstack/testing/pytest/marking.py +42 -15
- localstack/testing/pytest/path_filter.py +1 -1
- localstack/testing/pytest/stepfunctions/fixtures.py +4 -4
- localstack/testing/pytest/stepfunctions/utils.py +11 -10
- localstack/testing/pytest/util.py +1 -1
- localstack/testing/pytest/validation_tracking.py +3 -4
- localstack/testing/scenario/provisioning.py +11 -10
- localstack/testing/snapshots/transformer_utility.py +8 -3
- localstack/testing/testselection/matching.py +2 -2
- localstack/testing/testselection/opt_out.py +1 -1
- localstack/testing/testselection/scripts/filter_by_test_selection.py +1 -1
- localstack/testing/testselection/scripts/generate_test_selection.py +1 -1
- localstack/testing/testselection/testselection.py +2 -2
- localstack/utils/analytics/cli.py +2 -3
- localstack/utils/analytics/client.py +5 -5
- localstack/utils/analytics/events.py +2 -2
- localstack/utils/analytics/metadata.py +6 -4
- localstack/utils/analytics/metrics/counter.py +11 -18
- localstack/utils/analytics/metrics/registry.py +2 -2
- localstack/utils/analytics/publisher.py +4 -5
- localstack/utils/analytics/service_providers.py +19 -0
- localstack/utils/analytics/service_request_aggregator.py +4 -4
- localstack/utils/archives.py +12 -12
- localstack/utils/asyncio.py +2 -2
- localstack/utils/aws/arns.py +26 -31
- localstack/utils/aws/aws_responses.py +21 -28
- localstack/utils/aws/aws_stack.py +7 -12
- localstack/utils/aws/dead_letter_queue.py +4 -9
- localstack/utils/aws/message_forwarding.py +8 -11
- localstack/utils/aws/request_context.py +5 -6
- localstack/utils/aws/resources.py +1 -1
- localstack/utils/aws/templating.py +4 -4
- localstack/utils/batch_policy.py +4 -4
- localstack/utils/bootstrap.py +37 -30
- localstack/utils/catalog/catalog.py +139 -0
- localstack/utils/catalog/catalog_loader.py +119 -0
- localstack/utils/catalog/common.py +58 -0
- localstack/utils/catalog/plugins.py +28 -0
- localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
- localstack/utils/collections.py +33 -27
- localstack/utils/config_listener.py +2 -2
- localstack/utils/container_networking.py +5 -6
- localstack/utils/container_utils/container_client.py +156 -160
- localstack/utils/container_utils/docker_cmd_client.py +97 -81
- localstack/utils/container_utils/docker_sdk_client.py +75 -72
- localstack/utils/crypto.py +12 -13
- localstack/utils/diagnose.py +11 -12
- localstack/utils/docker_utils.py +11 -7
- localstack/utils/files.py +34 -15
- localstack/utils/functions.py +5 -4
- localstack/utils/http.py +14 -14
- localstack/utils/iputils.py +2 -1
- localstack/utils/json.py +21 -7
- localstack/utils/kinesis/kinesis_connector.py +2 -1
- localstack/utils/net.py +25 -17
- localstack/utils/no_exit_argument_parser.py +2 -2
- localstack/utils/numbers.py +9 -2
- localstack/utils/objects.py +15 -14
- localstack/utils/patch.py +14 -7
- localstack/utils/platform.py +2 -2
- localstack/utils/run.py +15 -14
- localstack/utils/scheduler.py +13 -12
- localstack/utils/server/tcp_proxy.py +2 -2
- localstack/utils/serving.py +3 -4
- localstack/utils/strings.py +15 -16
- localstack/utils/sync.py +126 -1
- localstack/utils/tagging.py +10 -8
- localstack/utils/testutil.py +17 -17
- localstack/utils/threads.py +3 -3
- localstack/utils/time.py +12 -4
- localstack/utils/urls.py +1 -3
- localstack/utils/xml.py +1 -1
- localstack/utils/xray/traceid.py +1 -1
- localstack/version.py +16 -3
- {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/METADATA +18 -13
- {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/RECORD +663 -655
- {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/entry_points.txt +8 -4
- localstack_core-4.10.1.dev12.dist-info/plux.json +1 -0
- localstack/packages/terraform.py +0 -47
- localstack/services/cloudformation/deploy.html +0 -144
- localstack/services/cloudformation/deploy_ui.py +0 -47
- localstack/services/cloudformation/plugins.py +0 -12
- localstack/services/lambda_/lambda_debug_mode/ldm.py +0 -375
- localstack/services/lambda_/lambda_debug_mode/ldm_config_file.py +0 -178
- localstack/services/lambda_/lambda_debug_mode/ldm_types.py +0 -11
- localstack/services/lambda_/lambda_debug_mode/ldm_utils.py +0 -43
- localstack_core-4.6.1.dev60.dist-info/plux.json +0 -1
- /localstack/{services/lambda_/lambda_debug_mode/__init__.py → testing/pytest/cloudformation/transformers.py} +0 -0
- {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack +0 -0
- {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.6.1.dev60.data → localstack_core-4.10.1.dev12.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/WHEEL +0 -0
- {localstack_core-4.6.1.dev60.dist-info → localstack_core-4.10.1.dev12.dist-info}/licenses/LICENSE.txt +0 -0
- {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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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``,
|
|
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
|
|
58
|
-
contain the logic for the XML
|
|
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
|
|
106
|
+
from collections.abc import Iterable, Iterator
|
|
83
107
|
from email.utils import formatdate
|
|
84
108
|
from struct import pack
|
|
85
|
-
from typing import
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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:
|
|
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
|
-
) ->
|
|
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:
|
|
394
|
-
error_code:
|
|
395
|
-
error_message:
|
|
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:
|
|
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:
|
|
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_
|
|
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:
|
|
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:
|
|
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) ->
|
|
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
|
-
) ->
|
|
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
|
-
) ->
|
|
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_
|
|
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 += "
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
1225
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
1241
|
-
|
|
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:
|
|
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
|
|
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
|
-
) ->
|
|
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:
|
|
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_
|
|
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:
|
|
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
|
|
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:
|
|
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
|
-
) ->
|
|
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:
|
|
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:
|
|
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
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
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(
|
|
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
|
|
2396
|
+
and service_protocol in service_specific_serializers[service.service_name]
|
|
1780
2397
|
):
|
|
1781
|
-
return service_specific_serializers[service.service_name][
|
|
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[
|
|
2401
|
+
return protocol_specific_serializers[service_protocol]()
|
|
1785
2402
|
|
|
1786
2403
|
|
|
1787
2404
|
def aws_response_serializer(
|
|
1788
|
-
service_name: str, operation: str, protocol:
|
|
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).
|