def field_decoder_factory( self, field: FieldDescriptor) -> Callable[[_Value], Any]: from venom.protocol import JSONProtocol if field.repeated: protocol = JSONProtocol(field.type) def _decode_value(msg): return protocol.unpacks(msg.encode('utf-8')) if field.key_type: return lambda dct: { k: _decode_value(v) for k, v in _cast_value(dict, dct).items() } return lambda lst: [ _decode_value(item) for item in _cast_value(list, lst) ] if issubclass(field.type, Message): protocol = JSONProtocol(field.type) def _decode_value(msg): return protocol.unpacks(msg.encode('utf-8')) return _decode_value if field.type is str: return lambda s: s if field.type is bytes: # TODO catch TypeError return lambda b: b64decode(b) return partial(_cast_value_from_string, field.type)
def test_encode_decode_map(self): class FooInner(Message): i = String() class Foo(Message): m = MapField(str) f = MapField(FooInner) message = Foo(m={'a': 'b'}, f={'k': FooInner(i='in')}) protocol = JSONProtocol(Foo) self.assertEqual(dict(message.m), {'a': 'b'}) self.assertEqual(dict(message.f), {'k': FooInner(i='in')}) self.assertEqual(protocol.encode(message), { 'm': { 'a': 'b' }, 'f': { 'k': { 'i': 'in' } } }) self.assertEqual( protocol.decode({ 'm': { 'a': 'b' }, 'f': { 'k': { 'i': 'in' } } }), message)
def test_pack(self): class Pet(Message): sound = String() protocol = JSONProtocol(Pet) self.assertEqual(protocol.pack(Pet()), b'{}') self.assertEqual(protocol.pack(Pet('hiss!')), b'{"sound":"hiss!"}')
def test_encode_zero_numeric(self): class Pet(Message): cuteness: float protocol = JSONProtocol(Pet) self.assertEqual(protocol.encode(Pet(0.0)), {'cuteness': 0.0}) self.assertEqual(protocol.decode({'cuteness': 0.0}), Pet(0.0))
def test_encode_message_json_name(self): class Pet(Message): size = Number(json_name='$size') protocol = JSONProtocol(Pet) pet = Pet() pet.size = 2.5 self.assertEqual(protocol.encode(pet), {'$size': 2.5}) self.assertEqual(protocol.decode({'$size': 2.5}), Pet(size=2.5))
def test_validation_field_string(self): class Foo(Message): string = String() protocol = JSONProtocol(Foo) with self.assertRaises(ValidationError) as e: protocol.decode({'string': None}) self.assertEqual(e.exception.description, "None is not of type 'str'") self.assertEqual(e.exception.path, ['string'])
def test_string_value(self): protocol = JSONProtocol(StringValue) self.assertEqual(protocol.encode(StringValue('hiss!')), 'hiss!') self.assertEqual(protocol.decode('hiss!'), StringValue('hiss!')) self.assertEqual(protocol.pack(StringValue()), b'""') self.assertEqual(protocol.pack(StringValue('hiss!')), b'"hiss!"') with self.assertRaises(ValidationError): protocol.decode(42)
def test_bool_value(self): protocol = JSONProtocol(BoolValue) self.assertEqual(protocol.encode(BoolValue()), False) self.assertEqual(protocol.encode(BoolValue(True)), True) self.assertEqual(protocol.decode(False), BoolValue(False)) with self.assertRaises(ValidationError): protocol.decode('hiss!')
def test_repeat(self): class Pet(Message): sounds: Repeat[str] protocol = JSONProtocol(Pet) self.assertEqual(protocol.encode(Pet(['hiss!', '(slither)'])), {'sounds': ['hiss!', '(slither)']}) self.assertEqual(protocol.decode({"sounds": ['hiss!']}), Pet(['hiss!'])) self.assertEqual(protocol.decode({}), Pet()) self.assertEqual(protocol.pack(Pet()), b'{}') self.assertEqual(protocol.pack(Pet([])), b'{"sounds":[]}') self.assertEqual(protocol.pack(Pet(['hiss!'])), b'{"sounds":["hiss!"]}') self.assertEqual(protocol.unpack(b'{}'), Pet()) self.assertEqual(protocol.unpack(b'{"sounds":["hiss!"]}'), Pet(['hiss!']))
def test_integer_value(self): protocol = JSONProtocol(IntegerValue) self.assertEqual(protocol.encode(IntegerValue(2)), 2) self.assertEqual(protocol.decode(2), IntegerValue(2)) with self.assertRaises(ValidationError): protocol.decode('hiss!')
def test_number_value(self): protocol = JSONProtocol(NumberValue) self.assertEqual(protocol.encode(NumberValue(2.5)), 2.5) self.assertEqual(protocol.decode(2.5), NumberValue(2.5)) with self.assertRaises(ValidationError): protocol.decode('hiss!')
def test_openapi_simple(self): class PetSimple(Message): id: int class PetServiceSimple(Service): class Meta: name = 'PetService' @http.GET('./pet/{id}') def get_pet(self, request: PetSimple) -> PetSimple: return request @http.POST('./pet') def create_pet_body(self, request: PetSimple) -> PetSimple: return request reflect = Reflect() reflect.add(PetServiceSimple) schema = make_openapi_schema(reflect) protocol = JSONProtocol(OpenAPISchema) with open(TEST_DIR + '/data/openapi_simple.json', 'rb') as f: schema_correct = protocol.unpack(f.read()) self.assertEqual(schema.paths, schema_correct.paths) self.assertEqual(schema.definitions, schema_correct.definitions)
def test_timestamp(self): protocol = JSONProtocol(Timestamp) self.assertEqual(protocol.decode('2017-10-10T12:34:56Z'), Timestamp(1507638896, 0)) self.assertEqual(protocol.encode(Timestamp(1507638896, 12345)), '2017-10-10T12:34:56.000012') with self.assertRaises(ValidationError): protocol.decode('yesterday')
def test_encode_message(self): class Pet(Message): sound: str protocol = JSONProtocol(Pet) self.assertEqual(protocol.encode(Pet('hiss!')), {'sound': 'hiss!'}) self.assertEqual(protocol.decode({'sound': 'meow'}), Pet('meow')) self.assertEqual(protocol.decode({}), Pet()) with self.assertRaises(ValidationError) as e: protocol.decode('bad') self.assertEqual(e.exception.description, "'bad' is not of type 'object'") self.assertEqual(e.exception.path, [])
def test_encode_repeat_field(self): class Pet(Message): sounds = repeated(String()) self.assertEqual(Pet.sounds.repeated, True) protocol = JSONProtocol(Pet) self.assertEqual(protocol.encode(Pet(['hiss!', 'slither'])), {'sounds': ['hiss!', 'slither']}) self.assertEqual(protocol.decode({'sounds': ['meow', 'purr']}), Pet(['meow', 'purr'])) self.assertEqual(protocol.decode({}), Pet()) self.assertEqual(protocol.encode(Pet()), {}) with self.assertRaises(ValidationError) as e: protocol.decode({'sounds': 'meow, purr'}) self.assertEqual(e.exception.description, "'meow, purr' is not of type 'list'") self.assertEqual(e.exception.path, ['sounds'])
def test_validation_path(self): protocol = JSONProtocol(Foo) with self.assertRaises(ValidationError) as e: protocol.decode({'string': 42}) self.assertEqual(e.exception.description, "42 is not of type 'str'") self.assertEqual(e.exception.path, ['string']) # FIXME With custom encoding/decoding for values this won't happen. with self.assertRaises(ValidationError) as e: protocol.decode({'stringValue': {'value': None}}) self.assertEqual(e.exception.description, "{'value': None} is not of type 'str'") self.assertEqual(e.exception.path, ['stringValue']) with self.assertRaises(ValidationError) as e: protocol.decode({'parent': {'stringValue': 42}}) self.assertEqual(e.exception.description, "42 is not of type 'str'") self.assertEqual(e.exception.path, ['parent', 'stringValue'])
def test_unpack_invalid_json(self): class Pet(Message): sound = String() protocol = JSONProtocol(Pet) with self.assertRaises(ValidationError) as e: protocol.unpack(b'') self.assertEqual(e.exception.description, "Invalid JSONProtocol: Expected object or value") self.assertEqual(e.exception.path, []) with self.assertRaises(ValidationError) as e: protocol.unpack(b'fs"ad')
def http_view_factory(venom: 'venom.rpc.Venom', method: venom.rpc.method.Method, protocol_factory: Type[Protocol], loop: 'asyncio.BaseEventLoop' = None): rpc_response = protocol_factory(method.response) rpc_error_response = protocol_factory(ErrorResponse) http_status = method.http_status http_field_locations = method.http_field_locations() http_request_body = JSONProtocol( method.request, FieldMask(http_field_locations[HTTPFieldLocation.BODY])) http_request_query = URIStringDictMessageTranscoder( URIStringProtocol, method.request, FieldMask(http_field_locations[HTTPFieldLocation.QUERY])) http_request_path = URIStringDictMessageTranscoder( URIStringProtocol, method.request, FieldMask(http_field_locations[HTTPFieldLocation.PATH])) if loop is None: loop = asyncio.get_event_loop() def view(**kwargs): try: request = http_request_body.unpack(flask.request.get_data()) http_request_query.decode(flask.request.args, request) http_request_path.decode(kwargs, request) response = loop.run_until_complete( venom.invoke(method, request, loop=loop)) return flask.Response(rpc_response.pack(response), mimetype=rpc_error_response.mime, status=http_status) except Error as e: return flask.Response(rpc_error_response.pack(e.format()), mimetype=rpc_error_response.mime, status=e.http_status) return view
def field_encoder_factory( self, field: FieldDescriptor) -> Callable[[Any], _Value]: from venom.protocol import JSONProtocol if field.repeated: protocol = JSONProtocol(field.type) if field.key_type: return lambda dct: { k: protocol.packs(v) for k, v in dct.items() } return lambda lst: [protocol.packs(v) for v in lst] if issubclass(field.type, Message): protocol = JSONProtocol(field.type) return protocol.packs if field.type is bytes: return lambda b: b64encode(b) return lambda x: str(x)
def test_field_mask(self): protocol = JSONProtocol(FieldMask) self.assertEqual(protocol.encode(FieldMask(['a', 'b'])), 'a,b') self.assertEqual(protocol.decode('a,b'), FieldMask(['a', 'b']))
def test_json_value(self): protocol = JSONProtocol(JSONValue) self.assertEqual(protocol.decode(True), JSONValue(True)) self.assertEqual(protocol.encode(JSONValue(1)), 1) self.assertEqual(protocol.decode('str'), JSONValue('str')) self.assertEqual(protocol.encode(JSONValue('str')), 'str') self.assertEqual(protocol.decode({'a': 'b'}), JSONValue({'a': 'b'})) self.assertEqual(protocol.encode(JSONValue({'a': 'b'})), {'a': 'b'}) self.assertEqual(protocol.decode([1, 2, 3]), JSONValue([1, 2, 3])) self.assertEqual(protocol.encode(JSONValue([1, 2, 3])), [1, 2, 3]) self.assertEqual( protocol.decode({ 'a': ['h', 'l'], 'b': [9, 8, 7], 'c': 1 }), JSONValue({ 'a': ['h', 'l'], 'b': [9, 8, 7], 'c': 1 })) self.assertEqual( protocol.encode( JSONValue({ 'a': ['h', 'l'], 'b': [9, 8, 7], 'c': 1 })), { 'a': ['h', 'l'], 'b': [9, 8, 7], 'c': 1 })