Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Latest commit

 

History

History
149 lines (101 loc) · 4.34 KB

tutorial.rst

File metadata and controls

149 lines (101 loc) · 4.34 KB

Tutorial

This tutorial is intended as an introduction to working with protobuf3.

Prerequisites

Before we start, make sure that you have the PyMongo distribution :doc:`installed <installation>`. 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 = "[email protected]"
>>> number = address.Person.PhoneNumber()
>>> number.number = "123"
>>> person.phone.append(number)

>>> person.encode_to_bytes()
b'\n\x08John Doe\x10\xd2\t\x1a\x10[email protected]"\x05\n\x03123'

>>> new_person = address.Person()
>>> new_person.parse_from_bytes(b'\n\x08John Doe\x10\xd2\t\x1a\x10[email protected]"\x05\n\x03123')
>>> assert new_person.id == 1234