Fields

Fields are assigned using theField class, instantiated within aMessage declaration.

Fields always have a type (either a primitive, a message, or an enum) and anumber.

importprotoclassComposer(proto.Message):given_name=proto.Field(proto.STRING,number=1)family_name=proto.Field(proto.STRING,number=2)classSong(proto.Message):composer=proto.Field(Composer,number=1)title=proto.Field(proto.STRING,number=2)lyrics=proto.Field(proto.STRING,number=3)year=proto.Field(proto.INT32,number=4)

For messages and enums, assign the message or enum class directly (as shownin the example above).

Note

For messages declared in the same module, it is also possible to use astring with the message class’ nameif the class is notyet declared, which allows for declaring messages out of order or withcircular references.

Repeated fields

Some fields are actually repeated fields. In protocol buffers, repeated fieldsare generally equivalent to typed lists. In protocol buffers, these aredeclared using therepeated keyword:

messageAlbum{repeatedSongsongs=1;stringpublisher=2;}

Declare them in Python using theRepeatedField class:

classAlbum(proto.Message):songs=proto.RepeatedField(Song,number=1)publisher=proto.Field(proto.STRING,number=2)

Note

Elementsmust be appended individually for repeated fields ofstruct.Value.

classRow(proto.Message):values=proto.RepeatedField(proto.MESSAGE,number=1,message=struct.Value,)>>>row=Row()>>>values=[struct_pb2.Value(string_value="hello")]>>>forvinvalues:>>>row.values.append(v)

Direct assignment will result in an error.

classRow(proto.Message):values=proto.RepeatedField(proto.MESSAGE,number=1,message=struct.Value,)>>>row=Row()>>>row.values=[struct_pb2.Value(string_value="hello")]Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>File"/usr/local/google/home/busunkim/github/python-automl/.nox/unit-3-8/lib/python3.8/site-packages/proto/message.py",line543,in__setattr__self._pb.MergeFrom(self._meta.pb(**{key:pb_value}))TypeError:Valuemustbeiterable

Map fields

Similarly, some fields are map fields. In protocol buffers, map fields areequivalent to typed dictionaries, where the keys are either strings orintegers, and the values can be any type. In protocol buffers, these usea specialmap syntax:

messageAlbum{map<uint32,Song>track_list=1;stringpublisher=2;}

Declare them in Python using theMapField class:

classAlbum(proto.Message):track_list=proto.MapField(proto.UINT32,Song,number=1)publisher=proto.Field(proto.STRING,number=2)

Oneofs (mutually-exclusive fields)

Protocol buffers allows certain fields to be declared as mutually exclusive.This is done by wrapping fields in aoneof syntax:

import"google/type/postal_address.proto";messageAlbumPurchase{Albumalbum=1;oneofdelivery{google.type.PostalAddresspostal_address=2;stringdownload_uri=3;}}

When using this syntax, protocol buffers will enforce that only one of thegiven fields is set on the message, and setting a field within the oneofwill clear any others.

Declare this in Python using theoneof keyword-argument, which takesa string (which should match for all fields within the oneof):

fromgoogle.type.postal_addressimportPostalAddressclassAlbumPurchase(proto.Message):album=proto.Field(Album,number=1)postal_address=proto.Field(PostalAddress,number=2,oneof='delivery')download_uri=proto.Field(proto.STRING,number=3,oneof='delivery')

Warning

oneof fieldsmust be declared consecutively, otherwise the Cimplementation of protocol buffers will reject the message. They need nothave consecutive field numbers, but they must be declared in consecutiveorder.

Warning

If a message is constructed with multiple variants of a singleoneof passedto its constructor, thelast keyword/value pair passed will be the finalvalue set.

This is consistent withPEP-468, which specifies the order that keyword argsare seen by called functions, and with the regular protocol buffers runtime,which exhibits the same behavior.

Example:

importprotoclassSong(proto.Message):name=proto.Field(proto.STRING,number=1,oneof="identifier")database_id=proto.Field(proto.STRING,number=2,oneof="identifier")s=Song(name="Canon in D minor",database_id="b5a37aad3")assert"database_id"insand"name"notinss=Song(database_id="e6aa708c7e",name="Little Fugue")assert"name"insand"database_id"notins

Optional fields

All fields in protocol buffers are optional, but it is often necessary tocheck for field presence. Sometimes legitimate values for fields can be falsy,so checking for truthiness is not sufficient. Proto3 v3.12.0 added theoptional keyword to field descriptions, which enables a mechanism forchecking field presence.

In proto plus, fields can be marked as optional by passingoptional=Truein the constructor. The messageclass then gains a field of the same namethat can be used to detect whether the field is present in messageinstances.

classSong(proto.Message):composer=proto.Field(Composer,number=1)title=proto.Field(proto.STRING,number=2)lyrics=proto.Field(proto.STRING,number=3)year=proto.Field(proto.INT32,number=4)performer=proto.Field(proto.STRING,number=5,optional=True)>>>s=Song(...composer={'given_name':'Johann','family_name':'Pachelbel'},...title='Canon in D',...year=1680,...genre=Genre.CLASSICAL,...)>>>Song.performerinsFalse>>>s.performer='Brahms'>>>Song.performerinsTrue>>>dels.performer>>>Song.performerinsFalse>>>s.performer=""# The mysterious, unnamed composer>>>Song.performerinsTrue

Under the hood, fields marked as optional are implemented via a syntheticone-variantoneof. See the protocolbuffersdocumentation for moreinformation.