Generated code explanation

This page describes exactly what Python definitions the protocol buffer compiler generates for any given protocol definition. Also, this page is very similar to same page from original implementation, so I describe only differences from original implementation.

Compiler invocation

There is two significant differences:

  1. –python3_out instead of –python_out.
  2. There is no _pb2 suffix in generated file names.

Messages

Message can be loaded from serialized form two ways:

  1. By calling class-method create_from_bytes
  2. By creating instance and then calling instance method parse_from_bytes

And can be serialized by calling encode_to_bytes

Fields

Instead of original implementation, this one doesn’t generate any constants with field numbers.

Singular fields

All works very similar to original implementation:

message.foo = 123
print message.foo

There is some difference how you check fields presence:

assert not 'foo' in message
message.foo = 123
assert 'foo' in message

Also, currently there is no way for removing field (look at PB3-23)

Singular Message Fields

There is no difference with original implementation

message Foo {
    optional Bar bar = 1;
}
message Bar {
    optional int32 i = 1;
}
foo = Foo()
assert not 'bar' in foo
foo.bar.i = 1
assert 'bar' in foo
assert foo.bar.i == 1

Repeated Fields

I copied this section from original documentation, but commented some lines, that currently not implemented:

  1. .extend()
  2. I’m not sure about comparison with list, I’ll check later and fix this moment
  3. Currently there is no easy way for delete item from list. I’m working on it
message Foo {
    repeated int32 nums = 1;
}
foo = Foo()
foo.nums.append(15)        # Appends one value
#foo.nums.extend([32, 47]) # Appends an entire list

assert len(foo.nums) == 3
assert foo.nums[0] == 15
assert foo.nums[1] == 32
#assert foo.nums == [15, 32, 47]

foo.nums[1] = 56    # Reassigns a value
assert foo.nums[1] == 56
for i in foo.nums:  # Loops and print
  print i
#del foo.nums[:]    # Clears list (works just like in a Python list)

Repeated Message Fields

It’s very similar to original implementation. Currently .add() isn’t supported

Enumerations

In Python 3.4 default enum is used, for previous Python version this implementation will require backported implementation enum34.

Some example:

message Foo {
    enum SomeEnum {
        VALUE_A = 1;
        VALUE_B = 5;
        VALUE_C = 1234;
    }
    optional SomeEnum bar = 1;
}

After generating you will receive following code:

from enum import Enum
from protobuf3.message import Message
from protobuf3.fields import EnumField


class Foo(Message):

    class SomeEnum(Enum):
        VALUE_A = 1
        VALUE_B = 5
        VALUE_C = 1234

Foo.add_field('bar', EnumField(field_number=1, optional=True, enum_cls=Foo.SomeEnum))

And how this works:

foo = Foo()
foo.bar = Foo.SomeEnum.VALUE_A
assert foo.bar.value == 1
assert foo.bar == Foo.SomeEnum.VALUE_A

Extensions

Messages with extension works very similar to messages without extensions. Look at this sample:

message Foo {
    extensions 100 to 199;
}

extend Foo {
    optional int32 bar = 123;
}
from protobuf3.fields import Int32Field
from protobuf3.message import Message


class Foo(Message):
    pass

Foo.add_field('bar', Int32Field(field_number=123, optional=True))

This should work even if message and extension declared in different files