def test_metadata_always_exists_on_rest_json_response(self): # ResponseMetadata is used for more than just the request id. It # should always get populated, even if the request doesn't seem to # have an id. parser = parsers.RestJSONParser() response = b'{"Str": "mystring"}' headers = {} output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Str': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }})) parsed = parser.parse( { 'body': response, 'headers': headers, 'status_code': 200 }, output_shape) expected = { 'Str': 'mystring', 'ResponseMetadata': { 'HTTPStatusCode': 200, 'HTTPHeaders': headers } } self.assertEqual(parsed, expected)
def test_metadata_always_exists_for_ec2(self): # ResponseMetadata is used for more than just the request id. It # should always get populated, even if the request doesn't seem to # have an id. parser = parsers.EC2QueryParser() response = ('<OperationNameResponse>' ' <Str>myname</Str>' '</OperationNameResponse>').encode('utf-8') output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Str': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }})) parsed = parser.parse( { 'headers': {}, 'body': response, 'status_code': 200 }, output_shape) expected = { 'Str': 'myname', 'ResponseMetadata': { 'HTTPStatusCode': 200, 'HTTPHeaders': {} } } self.assertEqual(parsed, expected)
def test_recursive_shape(self): shapes = { 'InputStructure': { 'type': 'structure', 'members': { 'A': { 'shape': 'RecursiveShape' } } }, 'RecursiveShape': { 'type': 'structure', 'members': { 'B': { 'shape': 'StringType' }, 'C': { 'shape': 'RecursiveShape' }, } }, 'StringType': { 'type': 'string' } } shape = model.StructureShape( shape_name='InputStructure', shape_model=shapes['InputStructure'], shape_resolver=model.ShapeResolver(shape_map=shapes)) self.assertIn('recursive', detect_shape_structure(shape))
def test_resolve_shape_references_with_member_traits(self): shape_map = { 'Foo': { 'type': 'structure', 'members': { 'Bar': { 'shape': 'StringType' }, 'Baz': { 'shape': 'StringType', 'locationName': 'other' }, } }, "StringType": { "type": "string" } } resolver = model.ShapeResolver(shape_map) shape = resolver.resolve_shape_ref({ 'shape': 'StringType', 'locationName': 'other' }) self.assertEqual(shape.serialization['name'], 'other') self.assertEqual(shape.name, 'StringType')
def test_response_metadata_parsed_for_ec2(self): parser = parsers.EC2QueryParser() response = ('<OperationNameResponse>' ' <Str>myname</Str>' ' <requestId>request-id</requestId>' '</OperationNameResponse>').encode('utf-8') output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Str': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }})) parsed = parser.parse( { 'headers': {}, 'body': response, 'status_code': 200 }, output_shape) # Note that the response metadata is normalized to match the query # protocol, even though this is not how it appears in the output. self.assertEqual( parsed, { 'Str': 'myname', 'ResponseMetadata': { 'RequestId': 'request-id', 'HTTPStatusCode': 200, 'HTTPHeaders': {} } })
def test_can_document_recursive_struct(self): # It's a little more work to set up a recursive # shape because DenormalizedStructureBuilder cannot handle # recursion. struct_shape = { 'type': 'structure', 'members': OrderedDict([ ('Recurse', {'shape': 'SubShape'}), ('Scalar', {'shape': 'String'}), ]), } shapes = { 'Top': struct_shape, 'String': {'type': 'string'}, 'SubShape': { 'type': 'structure', 'members': OrderedDict([ ('SubRecurse', {'shape': 'Top'}), ('Scalar', {'shape': 'String'}), ]), } } m = model.StructureShape( shape_name='Top', shape_model=struct_shape, shape_resolver=model.ShapeResolver(shapes)) argument = mock.Mock() argument.argument_model = m argument.name = 'foo' argument.cli_name = '--foo' generated_example = self.get_generated_example_for(argument) self.assertIn( 'Recurse={SubRecurse={( ... recursive ... ),Scalar=string},' 'Scalar=string},Scalar=string', generated_example)
def test_list_of_structures_with_triple_dots(self): list_shape = { 'type': 'list', 'member': { 'shape': 'StructShape' }, } shapes = { 'Top': list_shape, 'String': { 'type': 'string' }, 'StructShape': { 'type': 'structure', 'members': OrderedDict([ ('A', { 'shape': 'String' }), ('B', { 'shape': 'String' }), ]) } } m = model.ListShape(shape_name='Top', shape_model=list_shape, shape_resolver=model.ShapeResolver(shapes)) argument = mock.Mock() argument.argument_model = m argument.name = 'foo' argument.cli_name = '--foo' generated_example = self.get_generated_example_for(argument) self.assertIn('A=string,B=string ...', generated_example)
def test_shape_metadata(self): shapes = { 'ChangePasswordRequest': { 'type': 'structure', 'required': ['OldPassword', 'NewPassword'], 'members': { 'OldPassword': { 'shape': 'passwordType' }, 'NewPassword': { 'shape': 'passwordType' }, } }, 'passwordType': { "type": "string", "min": 1, "max": 128, "sensitive": True } } resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('ChangePasswordRequest') self.assertEqual(shape.metadata['required'], ['OldPassword', 'NewPassword']) member = shape.members['OldPassword'] self.assertEqual(member.metadata['min'], 1) self.assertEqual(member.metadata['max'], 128) self.assertEqual(member.metadata['sensitive'], True)
def test_serialization_cache(self): shape_map = { 'Foo': { 'type': 'structure', 'members': { 'Baz': { 'shape': 'StringType', 'locationName': 'other' }, } }, "StringType": { "type": "string" } } resolver = model.ShapeResolver(shape_map) shape = resolver.resolve_shape_ref({ 'shape': 'StringType', 'locationName': 'other' }) self.assertEqual(shape.serialization['name'], 'other') # serialization is computed on demand, and a cache is kept. # This is just verifying that trying to access serialization again # gives the same result. We don't actually care that it's cached, # we just care that the cache doesn't mess with correctness. self.assertEqual(shape.serialization['name'], 'other')
def test_shape_type_structure(self): shapes = { 'ChangePasswordRequest': { 'type': 'structure', 'members': { 'OldPassword': { 'shape': 'passwordType' }, 'NewPassword': { 'shape': 'passwordType' }, } }, 'passwordType': { "type": "string", } } resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('ChangePasswordRequest') self.assertEqual(shape.type_name, 'structure') self.assertEqual(shape.name, 'ChangePasswordRequest') self.assertEqual(list(sorted(shape.members)), ['NewPassword', 'OldPassword']) self.assertEqual(shape.members['OldPassword'].name, 'passwordType') self.assertEqual(shape.members['OldPassword'].type_name, 'string')
def setUp(self): self.shapes = { 'SetQueueAttributes': { 'type': 'structure', 'members': { 'MapExample': {'shape': 'StrToStrMap', 'locationName': 'Attribute'}, } }, 'SetQueueAttributes2': { 'type': 'structure', 'members': { 'MapExample': {'shape': 'StrToStrMap', 'locationName': 'Attribute2'}, } }, 'StrToStrMap': { 'type': 'map', 'key': {'shape': 'StringType', 'locationName': 'Name'}, 'value': {'shape': 'StringType', 'locationName': 'Value'}, 'flattened': True, 'name': 'NotAttribute', }, 'StringType': {'type': 'string'} } self.shape_resolver = model.ShapeResolver(self.shapes)
def test_response_no_initial_event_stream(self): parser = parsers.JSONParser() output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Payload': { 'shape': 'Payload' } } }, model.ShapeResolver({ 'Payload': { 'type': 'structure', 'members': [], 'eventstream': True } })) with self.assertRaises(parsers.ResponseParserError): response_dict = { 'status_code': 200, 'headers': {}, 'body': RawResponse(b''), 'context': { 'operation_name': 'TestOperation' } } parser.parse(response_dict, output_shape)
def test_shape_list(self): shapes = { 'mfaDeviceListType': { "type": "list", "member": { "shape": "MFADevice" }, }, 'MFADevice': { 'type': 'structure', 'members': { 'UserName': { 'shape': 'userNameType' } } }, 'userNameType': { 'type': 'string' } } resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('mfaDeviceListType') self.assertEqual(shape.member.type_name, 'structure') self.assertEqual(shape.member.name, 'MFADevice') self.assertEqual(list(shape.member.members), ['UserName'])
def test_list_of_structures_with_triple_dots(self): list_shape = { 'type': 'list', 'member': { 'shape': 'StructShape' }, } shapes = { 'Top': list_shape, 'String': { 'type': 'string' }, 'StructShape': { 'type': 'structure', 'members': OrderedDict([ ('A', { 'shape': 'String' }), ('B', { 'shape': 'String' }), ]) } } m = model.ListShape(shape_name='Top', shape_model=list_shape, shape_resolver=model.ShapeResolver(shapes)) generated_example = self.shorthand_documenter.generate_shorthand_example( '--foo', m) self.assertIn('A=string,B=string ...', generated_example)
def test_response_metadata_on_rest_json_response(self): parser = parsers.RestJSONParser() response = b'{"Str": "mystring"}' headers = {'x-amzn-requestid': 'request-id'} output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Str': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }})) parsed = parser.parse( { 'body': response, 'headers': headers, 'status_code': 200 }, output_shape) # Note that the response metadata is normalized to match the query # protocol, even though this is not how it appears in the output. self.assertEqual( parsed, { 'Str': 'mystring', 'ResponseMetadata': { 'RequestId': 'request-id', 'HTTPStatusCode': 200, 'HTTPHeaders': headers } })
def test_missing_type_key(self): shapes = { 'UnknownType': { 'NotTheTypeKey': 'someUnknownType' } } resolver = model.ShapeResolver(shapes) with self.assertRaises(model.InvalidShapeError): resolver.get_shape_by_name('UnknownType')
def test_shape_name_in_repr(self): shapes = { 'StringType': { 'type': 'string', } } resolver = model.ShapeResolver(shapes) self.assertIn('StringType', repr(resolver.get_shape_by_name('StringType')))
def test_exception_error_code(self): shapes = { 'FooException': { 'exception': True, 'type': 'structure', 'members': {} } } # Test without explicit error code resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('FooException') self.assertTrue(shape.metadata['exception']) self.assertEqual(shape.error_code, 'FooException') # Test with explicit error code shapes['FooException']['error'] = {'code': 'ExceptionCode'} resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('FooException') self.assertTrue(shape.metadata['exception']) self.assertEqual(shape.error_code, 'ExceptionCode')
def create_argument_model_from_schema(schema): # Given a JSON schems (described in schema.py), convert it # to a shape object from `botocore.model.Shape` that can be # used as the argument_model for the Argument classes below. transformer = SchemaTransformer() shapes_map = transformer.transform(schema) shape_resolver = model.ShapeResolver(shapes_map) # The SchemaTransformer guarantees that the top level shape # will always be named 'InputShape'. arg_shape = shape_resolver.get_shape_by_name('InputShape') return arg_shape
def setUp(self): self.error_shape = model.StructureShape( 'ErrorShape', { 'type': 'structure', 'exception': True, 'members': { 'ModeledField': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }}))
def create_arbitary_output_shape(self): output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'members': { 'Str': { 'shape': 'StringType', } } }, model.ShapeResolver({'StringType': { 'type': 'string' }})) return output_shape
def test_shape_overrides(self): shape_map = { "StringType": { "type": "string", "documentation": "Original documentation" } } resolver = model.ShapeResolver(shape_map) shape = resolver.get_shape_by_name('StringType') self.assertEqual(shape.documentation, 'Original documentation') shape = resolver.resolve_shape_ref({'shape': 'StringType', 'documentation': 'override'}) self.assertEqual(shape.documentation, 'override')
def test_resolve_shape_reference(self): shape_map = { 'Foo': { 'type': 'structure', 'members': { 'Bar': {'shape': 'StringType'}, 'Baz': {'shape': 'StringType'}, } }, "StringType": { "type": "string" } } resolver = model.ShapeResolver(shape_map) shape = resolver.resolve_shape_ref({'shape': 'StringType'}) self.assertEqual(shape.name, 'StringType') self.assertEqual(shape.type_name, 'string')
def test_response_metadata_parsed_for_query_service(self): parser = parsers.QueryParser() response = ( '<OperationNameResponse>' ' <OperationNameResult><Str>myname</Str></OperationNameResult>' ' <ResponseMetadata>' ' <RequestId>request-id</RequestId>' ' </ResponseMetadata>' '</OperationNameResponse>').encode('utf-8') output_shape = model.StructureShape( 'OutputShape', { 'type': 'structure', 'resultWrapper': 'OperationNameResult', 'members': { 'Str': { 'shape': 'StringType', }, 'Num': { 'shape': 'IntegerType', } } }, model.ShapeResolver({ 'StringType': { 'type': 'string', }, 'IntegerType': { 'type': 'integer', } })) parsed = parser.parse( { 'body': response, 'headers': {}, 'status_code': 200 }, output_shape) self.assertEqual( parsed, { 'Str': 'myname', 'ResponseMetadata': { 'RequestId': 'request-id', 'HTTPStatusCode': 200, 'HTTPHeaders': {} } })
def test_bad_shape_ref(self): # This is an example of a denormalized model, # which should raise an exception. shapes = { 'Struct': { 'type': 'structure', 'members': { 'A': {'type': 'string'}, 'B': {'type': 'string'}, } } } resolver = model.ShapeResolver(shapes) with self.assertRaises(model.InvalidShapeReferenceError): struct = resolver.get_shape_by_name('Struct') # Resolving the members will fail because # the 'A' and 'B' members are not shape refs. struct.members
def test_error_shape_metadata(self): shapes = { 'ResourceNotFoundException': { 'type': 'structure', 'members': { 'message': { 'shape': 'ErrorMessage', } }, 'exception': True, 'retryable': {'throttling': True} } } resolver = model.ShapeResolver(shapes) shape = resolver.get_shape_by_name('ResourceNotFoundException') self.assertEqual( shape.metadata, {'exception': True, 'retryable': {'throttling': True}} )
def test_shape_does_not_exist(self): resolver = model.ShapeResolver({}) with self.assertRaises(model.NoShapeFoundError): resolver.get_shape_by_name('NoExistShape')
def get_shape(self): loader = loaders.Loader() service_data = loader.load_service_model(SERVICE, 'service-2') shape_resolver = model.ShapeResolver(service_data.get('shapes', {})) operation_data = service_data['operations'][OPERATION] return shape_resolver.resolve_shape_ref(operation_data['output'])
def setUp(self): self.parser = parsers.EventStreamXMLParser() self.output_shape = model.StructureShape( 'EventStream', { 'eventstream': True, 'type': 'structure', 'members': { 'EventA': { 'shape': 'EventAStructure' }, 'EventB': { 'shape': 'EventBStructure' }, 'EventC': { 'shape': 'EventCStructure' }, 'EventD': { 'shape': 'EventDStructure' }, } }, model.ShapeResolver({ 'EventAStructure': { 'event': True, 'type': 'structure', 'members': { 'Stats': { 'shape': 'StatsStructure', 'eventpayload': True }, 'Header': { 'shape': 'IntShape', 'eventheader': True } } }, 'EventBStructure': { 'event': True, 'type': 'structure', 'members': { 'Body': { 'shape': 'BlobShape', 'eventpayload': True } } }, 'EventCStructure': { 'event': True, 'type': 'structure', 'members': { 'Body': { 'shape': 'StringShape', 'eventpayload': True } } }, 'EventDStructure': { 'event': True, 'type': 'structure', 'members': { 'StringField': { 'shape': 'StringShape' }, 'IntField': { 'shape': 'IntShape' }, 'Header': { 'shape': 'IntShape', 'eventheader': True } } }, 'StatsStructure': { 'type': 'structure', 'members': { 'StringField': { 'shape': 'StringShape' }, 'IntField': { 'shape': 'IntShape' } } }, 'BlobShape': { 'type': 'blob' }, 'StringShape': { 'type': 'string' }, 'IntShape': { 'type': 'integer' } }))