Package: proxo
ProxoExtend protobuf message with custom methods properties and additional
attributesTL;DRfromproxoimportMessageProxy,encode,decodeclassPerson(MessageProxy):proto=addressbook_pb2.Person# it can be more complex, like pattern matching, see below@propertydeffirstname(self):returnself.name.split(' ')[0]p=Person(name='Test Me')assertp.firstname=='Test'assertdecode(encode(p))==pUsageGiven the addressbook protobuf definitionpackagetutorial;messagePerson{requiredstringname=1;requiredint32id=2;optionalstringemail=3;enumPhoneType{MOBILE=0;HOME=1;WORK=2;}messagePhoneNumber{requiredstringnumber=1;optionalPhoneTypetype=2[default=HOME];}repeatedPhoneNumberphone=4;}messageAddressBook{repeatedPersonperson=1;}The traditional wayimportaddressbook_pb2person=addressbook_pb2.Person()person.id=1234person.name="John Doe"person.email="jdoe@example.com"phone=person.phone.add()phone.number="555-4321"phone.type=addressbook_pb2.Person.HOMEvia Proxo.dict_to_protobuffromproxoimportdict_to_protobuf,protobuf_to_dictdata={'id':124,'name':'John Doe','email':'jdoe@example.com','phone':{'number':'555-4321','type':'HOME'}}proto=dict_to_protobuf(data,addressbook_pb2.Person)assertperson==proto# converting backmapping=protobuf_to_dict(proto)mapping['phone']['number']mapping.phone.number# using dot notationassertmapping==datavia extending Proxo.MessageProxyfromproxoimportMessageProxy,encode,decode# note that non defined types will be automatically proxied tooclassPerson(MessageProxy):proto=addressbook_pb2.Person# it can be more complex, like pattern matching, see below@propertydeffirstname(self):returnself.name.split(' ')[0]defcall(self):try:print('calling{}'.format(self.firstname))do_voip_call(self.phone.number)except:print('failed calling{}on his/her{}number'.format(self.firstname,self.phone.type.lower))obj=Person(id=124,name='John Doe',phone={'number':'555-4321','type':'HOME'})obj.phone.type='MOBILE'assertobj.firsname=='John'proto=encode(obj)john=decode(proto)# lets bother himjohn.call()More Complicated Exampleimportoperatorfromuuidimportuuid4fromfunctoolsimportpartialfromproxoimportMessageProxyclassScalar(MessageProxy):proto=mesos_pb2.Value.ScalarclassResource(MessageProxy):proto=mesos_pb2.Resource# can be classclassScalarResource(Resource):proto=mesos_pb2.Resource(type=mesos_pb2.Value.SCALAR)# or partially set instancedef__init__(self,value=None,**kwargs):super(Resource,self).__init__(**kwargs)ifvalueisnotNone:self.scalar=Scalar(value=value)def__cmp__(self,other):first,second=float(self),float(other)iffirst<second:return-1eliffirst>second:return1else:return0def__repr__(self):return"<{}:{}>".format(self.__class__.__name__,self.scalar.value)def__float__(self):returnfloat(self.scalar.value)@classmethoddef_op(cls,op,first,second):value=op(float(first),float(second))returncls(value=value)def__add__(self,other):returnself._op(operator.add,self,other)def__radd__(self,other):returnself._op(operator.add,other,self)def__sub__(self,other):returnself._op(operator.sub,self,other)def__rsub__(self,other):returnself._op(operator.sub,other,self)def__mul__(self,other):returnself._op(operator.mul,self,other)def__rmul__(self,other):returnself._op(operator.mul,other,self)def__truediv__(self,other):returnself._op(operator.truediv,self,other)def__rtruediv__(self,other):returnself._op(operator.truediv,other,self)def__iadd__(self,other):self.scalar.value=float(self._op(operator.add,self,other))returnselfdef__isub__(self,other):self.scalar.value=float(self._op(operator.sub,self,other))returnselfclassCpus(ScalarResource):proto=mesos_pb2.Resource(name='cpus',type=mesos_pb2.Value.SCALAR)classMem(ScalarResource):proto=mesos_pb2.Resource(name='mem',type=mesos_pb2.Value.SCALAR)classDisk(ScalarResource):proto=mesos_pb2.Resource(name='disk',type=mesos_pb2.Value.SCALAR)