Tutorial¶
This tutorial is intended as an introduction to working with protobuf3.
Prerequisites¶
Before we start, make sure that you have the PyMongo distribution installed. In the Python shell, the following should run without raising an exception:
>>> import protobuf3
This tutorial also assumes that you have installed protobuf compiler. The following command should run and show libprotobuf version:
$ protoc --version
Defining your protocol format¶
I don’t want to copy-paste official protobuf tutorials, so if you want some explanation for this file, you can find it here.
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
Compiling your protocol buffers¶
It’s very similar with original protobuf implementation. There is only one different thing: use –python3_out instead of –python_out
Generated code example¶
Protobuf compiler will generate this code for example .proto file
from protobuf3.message import Message
from protobuf3.fields import StringField, EnumField, Int32Field, MessageField
from enum import Enum
class Person(Message):
class PhoneType(Enum):
MOBILE = 0
HOME = 1
WORK = 2
class PhoneNumber(Message):
pass
class AddressBook(Message):
pass
Person.PhoneNumber.add_field('number', StringField(field_number=1, required=True))
Person.PhoneNumber.add_field('type', EnumField(field_number=2, optional=True, enum_cls=Person.PhoneType, default=Person.PhoneType.HOME))
Person.add_field('name', StringField(field_number=1, required=True))
Person.add_field('id', Int32Field(field_number=2, required=True))
Person.add_field('email', StringField(field_number=3, optional=True))
Person.add_field('phone', MessageField(field_number=4, repeated=True, message_cls=Person.PhoneNumber))
AddressBook.add_field('person', MessageField(field_number=1, repeated=True, message_cls=Person))
But this library also support django-style code for defining data model (this form is more readable). Same code, but hand-written using this style:
from protobuf3.message import Message
from protobuf3.fields import StringField, EnumField, Int32Field, MessageField
from enum import Enum
class Person(Message):
class PhoneType(Enum):
MOBILE = 0
HOME = 1
WORK = 2
class PhoneNumber(Message):
number = StringField(field_number=1, required=True)
type = EnumField(field_number=2, optional=True, enum_cls=Person.PhoneType, default=Person.PhoneType.HOME)
name = StringField(field_number=1, required=True)
id = Int32Field(field_number=2, required=True)
email = StringField(field_number=3, optional=True)
phone = MessageField(field_number=4, repeated=True, message_cls=Person.PhoneNumber)
class AddressBook(Message):
person = MessageField(field_number=1, repeated=True, message_cls=Person)
The Protocol Buffer API¶
It’s very similar to original implementation. Currently there is some difference how repeated field work (probably I make some comparability changes).
>>> person = address.Person()
>>> person.id = 1234
>>> person.name = "John Doe"
>>> person.email = "jdoe@example.com"
>>> number = address.Person.PhoneNumber()
>>> number.number = "123"
>>> person.phone.append(number)
>>> person.encode_to_bytes()
b'\n\x08John Doe\x10\xd2\t\x1a\x10jdoe@example.com"\x05\n\x03123'
>>> new_person = address.Person()
>>> new_person.parse_from_bytes(b'\n\x08John Doe\x10\xd2\t\x1a\x10jdoe@example.com"\x05\n\x03123')
>>> assert new_person.id == 1234