From c1463fe41a88aa723013b40b4855b903198f8394 Mon Sep 17 00:00:00 2001 From: Kaidi He <73141777+kaidih@users.noreply.github.com> Date: Tue, 27 Oct 2020 13:42:10 -0700 Subject: [PATCH 1/3] Mq event source (#60) * Support AmazonMQ as event source * Set black hook language version to python3 --- docs/cloudformation_compatibility.rst | 10 +++ docs/internals/generated_resources.rst | 30 ++++++++ samtranslator/model/eventsources/pull.py | 23 ++++-- samtranslator/model/lambda_.py | 2 + .../validator/sam_schema/schema.json | 23 ++++++ tests/translator/input/amq.yaml | 17 +++++ .../input/error_missing_broker.yaml | 16 +++++ tests/translator/output/amq.json | 70 +++++++++++++++++++ tests/translator/output/aws-cn/amq.json | 70 +++++++++++++++++++ tests/translator/output/aws-us-gov/amq.json | 70 +++++++++++++++++++ .../output/error_missing_broker.json | 6 ++ .../output/error_missing_queue.json | 4 +- .../output/error_missing_stream.json | 4 +- tests/translator/test_translator.py | 14 ++-- 14 files changed, 345 insertions(+), 14 deletions(-) create mode 100644 tests/translator/input/amq.yaml create mode 100644 tests/translator/input/error_missing_broker.yaml create mode 100644 tests/translator/output/amq.json create mode 100644 tests/translator/output/aws-cn/amq.json create mode 100644 tests/translator/output/aws-us-gov/amq.json create mode 100644 tests/translator/output/error_missing_broker.json diff --git a/docs/cloudformation_compatibility.rst b/docs/cloudformation_compatibility.rst index 50b973612..5cac0920a 100644 --- a/docs/cloudformation_compatibility.rst +++ b/docs/cloudformation_compatibility.rst @@ -108,6 +108,16 @@ StartingPosition All BatchSize All ======================== ================================== ======================== +MQ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +======================== ================================== ======================== + Property Name Intrinsic(s) Supported Reasons +======================== ================================== ======================== +Broker All +Queues All +SourceAccessConfigurations All +======================== ================================== ======================== + MSK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ======================== ================================== ======================== diff --git a/docs/internals/generated_resources.rst b/docs/internals/generated_resources.rst index 760d52a15..3d03cd148 100644 --- a/docs/internals/generated_resources.rst +++ b/docs/internals/generated_resources.rst @@ -326,6 +326,36 @@ AWS::Lambda::Permission MyFunction\ **MyTrigger**\ Permission AWS::Lambda::EventSourceMapping MyFunction\ **MyTrigger** ================================== ================================ +MQ +^^^^^^^ + +Example: + +.. code:: yaml + + MyFunction: + Type: AWS::Serverless::Function + Properties: + ... + Events: + MyTrigger: + Type: MQ + Properties: + Broker: arn:aws:mq:us-east-2:123456789012:broker:MyBroker:b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9 + SourceAccessConfigurations: + Type: BASIC_AUTH + URI: arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c + ... + +Additional generated resources: + +================================== ================================ +CloudFormation Resource Type Logical ID +================================== ================================ +AWS::Lambda::Permission MyFunction\ **MyTrigger**\ Permission +AWS::Lambda::EventSourceMapping MyFunction\ **MyTrigger** +================================== ================================ + MSK ^^^^^^^ diff --git a/samtranslator/model/eventsources/pull.py b/samtranslator/model/eventsources/pull.py index f629b56c0..7ead57569 100644 --- a/samtranslator/model/eventsources/pull.py +++ b/samtranslator/model/eventsources/pull.py @@ -10,7 +10,7 @@ class PullEventSource(ResourceMacro): """Base class for pull event sources for SAM Functions. - The pull events are Kinesis Streams, DynamoDB Streams, Kafka Streams and SQS Queues. All of these correspond to an + The pull events are Kinesis Streams, DynamoDB Streams, Kafka Topics, ActiveMQ Queues and SQS Queues. All of these correspond to an EventSourceMapping in Lambda, and require that the execution role be given to Kinesis Streams, DynamoDB Streams, or SQS Queues, respectively. @@ -31,6 +31,9 @@ class PullEventSource(ResourceMacro): "DestinationConfig": PropertyType(False, is_type(dict)), "ParallelizationFactor": PropertyType(False, is_type(int)), "Topics": PropertyType(False, is_type(list)), + "Broker": PropertyType(False, is_str()), + "Queues": PropertyType(False, is_type(list)), + "SourceAccessConfigurations": PropertyType(False, is_type(list)), } def get_policy_arn(self): @@ -60,16 +63,17 @@ def to_cloudformation(self, **kwargs): except NotImplementedError: function_name_or_arn = function.get_runtime_attr("arn") - if not self.Stream and not self.Queue: + if not self.Stream and not self.Queue and not self.Broker: raise InvalidEventException( - self.relative_id, "No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) provided." + self.relative_id, + "No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided.", ) if self.Stream and not self.StartingPosition: raise InvalidEventException(self.relative_id, "StartingPosition is required for Kinesis, DynamoDB and MSK.") lambda_eventsourcemapping.FunctionName = function_name_or_arn - lambda_eventsourcemapping.EventSourceArn = self.Stream or self.Queue + lambda_eventsourcemapping.EventSourceArn = self.Stream or self.Queue or self.Broker lambda_eventsourcemapping.StartingPosition = self.StartingPosition lambda_eventsourcemapping.BatchSize = self.BatchSize lambda_eventsourcemapping.Enabled = self.Enabled @@ -79,6 +83,8 @@ def to_cloudformation(self, **kwargs): lambda_eventsourcemapping.MaximumRecordAgeInSeconds = self.MaximumRecordAgeInSeconds lambda_eventsourcemapping.ParallelizationFactor = self.ParallelizationFactor lambda_eventsourcemapping.Topics = self.Topics + lambda_eventsourcemapping.Queues = self.Queues + lambda_eventsourcemapping.SourceAccessConfigurations = self.SourceAccessConfigurations destination_config_policy = None if self.DestinationConfig: @@ -170,3 +176,12 @@ class MSK(PullEventSource): def get_policy_arn(self): return ArnGenerator.generate_aws_managed_policy_arn("service-role/AWSLambdaMSKExecutionRole") + + +class MQ(PullEventSource): + """MQ event source.""" + + resource_type = "MQ" + + def get_policy_arn(self): + return ArnGenerator.generate_aws_managed_policy_arn("service-role/AWSLambdaAMQExecutionRole") diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index 45db54522..0cb75661c 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -70,6 +70,8 @@ class LambdaEventSourceMapping(Resource): "ParallelizationFactor": PropertyType(False, is_type(int)), "StartingPosition": PropertyType(False, is_str()), "Topics": PropertyType(False, is_type(list)), + "Queues": PropertyType(False, is_type(list)), + "SourceAccessConfigurations": PropertyType(False, is_type(list)), } runtime_attrs = {"name": lambda self: ref(self.logical_id)} diff --git a/samtranslator/validator/sam_schema/schema.json b/samtranslator/validator/sam_schema/schema.json index 19699acae..b0c83761c 100644 --- a/samtranslator/validator/sam_schema/schema.json +++ b/samtranslator/validator/sam_schema/schema.json @@ -477,6 +477,9 @@ { "$ref": "#/definitions/AWS::Serverless::Function.MSKEvent" }, + { + "$ref": "#/definitions/AWS::Serverless::Function.MQEvent" + }, { "$ref": "#/definitions/AWS::Serverless::Function.SQSEvent" }, @@ -609,6 +612,26 @@ ], "type": "object" }, + "AWS::Serverless::Function.MQEvent": { + "additionalProperties": false, + "properties": { + "Broker": { + "type": "string" + }, + "Queues": { + "type": "array" + }, + "SourceAccessConfigurations": { + "type": "array" + } + }, + "required": [ + "Broker", + "Queues", + "SourceAccessConfigurations" + ], + "type": "object" + }, "AWS::Serverless::Function.SQSEvent": { "additionalProperties": false, diff --git a/tests/translator/input/amq.yaml b/tests/translator/input/amq.yaml new file mode 100644 index 000000000..00d28b841 --- /dev/null +++ b/tests/translator/input/amq.yaml @@ -0,0 +1,17 @@ +Resources: + MQFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/queues.zip + Handler: queue.mq_handler + Runtime: python2.7 + Events: + MyMQQueue: + Type: MQ + Properties: + Broker: arn:aws:mq:us-east-2:123456789012:broker:MyBroker:b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9 + Queues: + - "Queue1" + SourceAccessConfigurations: + - Type: BASIC_AUTH + URI: arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c \ No newline at end of file diff --git a/tests/translator/input/error_missing_broker.yaml b/tests/translator/input/error_missing_broker.yaml new file mode 100644 index 000000000..143b2ca27 --- /dev/null +++ b/tests/translator/input/error_missing_broker.yaml @@ -0,0 +1,16 @@ +Resources: + MQFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/queues.zip + Handler: queue.mq_handler + Runtime: python2.7 + Events: + MyMQQueue: + Type: MQ + Properties: + Queues: + - "Queue1" + SourceAccessConfigurations: + - Type: BASIC_AUTH + URI: arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c \ No newline at end of file diff --git a/tests/translator/output/amq.json b/tests/translator/output/amq.json new file mode 100644 index 000000000..796785adc --- /dev/null +++ b/tests/translator/output/amq.json @@ -0,0 +1,70 @@ +{ + "Resources": { + "MQFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "queues.zip" + }, + "Handler": "queue.mq_handler", + "Role": { + "Fn::GetAtt": [ + "MQFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [{ + "Value": "SAM", + "Key": "lambda:createdBy" + }] + } + }, + "MQFunctionMyMQQueue": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "EventSourceArn": "arn:aws:mq:us-east-2:123456789012:broker:MyBroker:b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9", + "FunctionName": { + "Ref": "MQFunction" + }, + "Queues": ["Queue1"], + "SourceAccessConfigurations": [ + { + "Type": "BASIC_AUTH", + "URI": "arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c" + } + ] + } + }, + "MQFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/service-role/AWSLambdaAMQExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [{ + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + }] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/amq.json b/tests/translator/output/aws-cn/amq.json new file mode 100644 index 000000000..b75267663 --- /dev/null +++ b/tests/translator/output/aws-cn/amq.json @@ -0,0 +1,70 @@ +{ + "Resources": { + "MQFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "queues.zip" + }, + "Handler": "queue.mq_handler", + "Role": { + "Fn::GetAtt": [ + "MQFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [{ + "Value": "SAM", + "Key": "lambda:createdBy" + }] + } + }, + "MQFunctionMyMQQueue": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "EventSourceArn": "arn:aws:mq:us-east-2:123456789012:broker:MyBroker:b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9", + "FunctionName": { + "Ref": "MQFunction" + }, + "Queues": ["Queue1"], + "SourceAccessConfigurations": [ + { + "Type": "BASIC_AUTH", + "URI": "arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c" + } + ] + } + }, + "MQFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaAMQExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [{ + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + }] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/amq.json b/tests/translator/output/aws-us-gov/amq.json new file mode 100644 index 000000000..5a42ee959 --- /dev/null +++ b/tests/translator/output/aws-us-gov/amq.json @@ -0,0 +1,70 @@ +{ + "Resources": { + "MQFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "queues.zip" + }, + "Handler": "queue.mq_handler", + "Role": { + "Fn::GetAtt": [ + "MQFunctionRole", + "Arn" + ] + }, + "Runtime": "python2.7", + "Tags": [{ + "Value": "SAM", + "Key": "lambda:createdBy" + }] + } + }, + "MQFunctionMyMQQueue": { + "Type": "AWS::Lambda::EventSourceMapping", + "Properties": { + "EventSourceArn": "arn:aws:mq:us-east-2:123456789012:broker:MyBroker:b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9", + "FunctionName": { + "Ref": "MQFunction" + }, + "Queues": ["Queue1"], + "SourceAccessConfigurations": [ + { + "Type": "BASIC_AUTH", + "URI": "arn:aws:secretsmanager:us-west-2:123456789012:secret:my-path/my-secret-name-1a2b3c" + } + ] + } + }, + "MQFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaAMQExecutionRole" + ], + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [{ + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + }] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/error_missing_broker.json b/tests/translator/output/error_missing_broker.json new file mode 100644 index 000000000..136ac3800 --- /dev/null +++ b/tests/translator/output/error_missing_broker.json @@ -0,0 +1,6 @@ +{ + "errors": [{ + "errorMessage": "Resource with id [MQFunction] is invalid. Event with id [MyMQQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." + }], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MQFunction] is invalid. Event with id [MyMQQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." +} \ No newline at end of file diff --git a/tests/translator/output/error_missing_queue.json b/tests/translator/output/error_missing_queue.json index 561dfefcf..4a7ba1f7a 100644 --- a/tests/translator/output/error_missing_queue.json +++ b/tests/translator/output/error_missing_queue.json @@ -1,6 +1,6 @@ { "errors": [{ - "errorMessage": "Resource with id [SQSFunction] is invalid. Event with id [MySqsQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) provided." + "errorMessage": "Resource with id [SQSFunction] is invalid. Event with id [MySqsQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." }], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [SQSFunction] is invalid. Event with id [MySqsQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) provided." + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [SQSFunction] is invalid. Event with id [MySqsQueue] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." } \ No newline at end of file diff --git a/tests/translator/output/error_missing_stream.json b/tests/translator/output/error_missing_stream.json index 3dd94a47e..f85ff25e8 100644 --- a/tests/translator/output/error_missing_stream.json +++ b/tests/translator/output/error_missing_stream.json @@ -1,6 +1,6 @@ { "errors": [{ - "errorMessage": "Resource with id [DynamoDBFunction] is invalid. Event with id [MyDDBStream] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) provided." + "errorMessage": "Resource with id [DynamoDBFunction] is invalid. Event with id [MyDDBStream] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." }], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [DynamoDBFunction] is invalid. Event with id [MyDDBStream] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) provided." + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [DynamoDBFunction] is invalid. Event with id [MyDDBStream] is invalid. No Queue (for SQS) or Stream (for Kinesis, DynamoDB or MSK) or Broker (for ActiveMQ) provided." } \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 56775c0cf..8bc87fcf0 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -157,6 +157,7 @@ class TestTranslatorEndToEnd(TestCase): "cloudwatchlog", "streams", "sqs", + "amq", "simpletable", "simpletable_with_sse", "implicit_api", @@ -338,7 +339,7 @@ def test_transform_success(self, testcase, partition_with_region): output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -420,7 +421,7 @@ def test_transform_success_openapi3(self, testcase, partition_with_region): output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -479,7 +480,7 @@ def test_transform_success_resource_policy(self, testcase, partition_with_region } output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -604,6 +605,7 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw "error_function_invalid_request_parameters", "error_invalid_logical_id", "error_layer_invalid_properties", + "error_missing_broker", "error_missing_queue", "error_missing_startingposition", "error_missing_stream", @@ -757,7 +759,7 @@ def test_swagger_body_sha_gets_recomputed(): output_fragment = transform(document, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) deployment_key = get_deployment_key(output_fragment) assert deployment_key @@ -793,7 +795,7 @@ def test_swagger_definitionuri_sha_gets_recomputed(): output_fragment = transform(document, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) deployment_key = get_deployment_key(output_fragment) assert deployment_key @@ -875,7 +877,7 @@ def _do_transform(self, document, parameter_values=get_template_parameter_values mock_policy_loader = get_policy_mock() output_fragment = transform(document, parameter_values, mock_policy_loader) - print(json.dumps(output_fragment, indent=2)) + print (json.dumps(output_fragment, indent=2)) return output_fragment From df3ca29ca09fd34318cb3a42131f4315c5878e0f Mon Sep 17 00:00:00 2001 From: Wing Fung Lau <4760060+hawflau@users.noreply.github.com> Date: Thu, 5 Nov 2020 08:56:22 -0800 Subject: [PATCH 2/3] chore: version bump (#64) --- samtranslator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/__init__.py b/samtranslator/__init__.py index 9813fabb0..c347ac29b 100644 --- a/samtranslator/__init__.py +++ b/samtranslator/__init__.py @@ -1 +1 @@ -__version__ = "1.27.0" +__version__ = "1.29.0" From 3f9082de7f47f5b5d2c61a07c2a0aad3c28834bc Mon Sep 17 00:00:00 2001 From: Wing Fung Lau <4760060+hawflau@users.noreply.github.com> Date: Thu, 5 Nov 2020 10:53:43 -0800 Subject: [PATCH 3/3] Black reformat --- tests/translator/test_translator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 8bc87fcf0..deedc6336 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -339,7 +339,7 @@ def test_transform_success(self, testcase, partition_with_region): output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -421,7 +421,7 @@ def test_transform_success_openapi3(self, testcase, partition_with_region): output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -480,7 +480,7 @@ def test_transform_success_resource_policy(self, testcase, partition_with_region } output_fragment = transform(manifest, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) # Only update the deployment Logical Id hash in Py3. if sys.version_info.major >= 3: @@ -759,7 +759,7 @@ def test_swagger_body_sha_gets_recomputed(): output_fragment = transform(document, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) deployment_key = get_deployment_key(output_fragment) assert deployment_key @@ -795,7 +795,7 @@ def test_swagger_definitionuri_sha_gets_recomputed(): output_fragment = transform(document, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) deployment_key = get_deployment_key(output_fragment) assert deployment_key @@ -877,7 +877,7 @@ def _do_transform(self, document, parameter_values=get_template_parameter_values mock_policy_loader = get_policy_mock() output_fragment = transform(document, parameter_values, mock_policy_loader) - print (json.dumps(output_fragment, indent=2)) + print(json.dumps(output_fragment, indent=2)) return output_fragment