Search code examples
pythonpython-3.xprotocol-buffersprotobuf-python

Incorrect Protobuf classes are getting generated


I am trying out my first Protobuf sample code from the Protobuf documentation for Python. https://protobuf.dev/getting-started/pythontutorial/

This is my .proto file.

syntax = "proto2";

package tutorial;

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    PHONE_TYPE_UNSPECIFIED = 0;
    PHONE_TYPE_MOBILE = 1;
    PHONE_TYPE_HOME = 2;
    PHONE_TYPE_WORK = 3;
  }

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2 [default = PHONE_TYPE_HOME];
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

I navigated to the folder of the proto file in terminal and passed the below command.

protoc --python_out=../Generated addressbook.proto

Below is the generated python file.

# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: addressbook.proto
# Protobuf Python Version: 4.25.2
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()




DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11\x61\x64\x64ressbook.proto\x12\x08tutorial\"\xa3\x02\n\x06Person\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x05\x12\r\n\x05\x65mail\x18\x03 \x01(\t\x12,\n\x06phones\x18\x04 \x03(\x0b\x32\x1c.tutorial.Person.PhoneNumber\x1aX\n\x0bPhoneNumber\x12\x0e\n\x06number\x18\x01 \x01(\t\x12\x39\n\x04type\x18\x02 \x01(\x0e\x32\x1a.tutorial.Person.PhoneType:\x0fPHONE_TYPE_HOME\"h\n\tPhoneType\x12\x1a\n\x16PHONE_TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11PHONE_TYPE_MOBILE\x10\x01\x12\x13\n\x0fPHONE_TYPE_HOME\x10\x02\x12\x13\n\x0fPHONE_TYPE_WORK\x10\x03\"/\n\x0b\x41\x64\x64ressBook\x12 \n\x06people\x18\x01 \x03(\x0b\x32\x10.tutorial.Person')

_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'addressbook_pb2', _globals)
if _descriptor._USE_C_DESCRIPTORS == False:
  DESCRIPTOR._options = None
  _globals['_PERSON']._serialized_start=32
  _globals['_PERSON']._serialized_end=323
  _globals['_PERSON_PHONENUMBER']._serialized_start=129
  _globals['_PERSON_PHONENUMBER']._serialized_end=217
  _globals['_PERSON_PHONETYPE']._serialized_start=219
  _globals['_PERSON_PHONETYPE']._serialized_end=323
  _globals['_ADDRESSBOOK']._serialized_start=325
  _globals['_ADDRESSBOOK']._serialized_end=372
# @@protoc_insertion_point(module_scope)

I don't find any generated classes and am not sure how to serialize or parse my data with this generated file.


Solution

  • In Python, protoc generates metaclasses (see Python Generated Code).

    Generally (!) I'd discourage placing protoc-generated stubs anywhere other than ${PWD}. But, because you used Generated, you will want to add an empty __init__.py file in Generated to create a Python package.

    .
    ├── addressbook.proto
    ├── Generated
    │   ├── addressbook_pb2.py
    │   ├── addressbook_pb2.pyi
    │   └── __init__.py
    └── main.py
    

    Then you could e.g.:

    from Generated import addressbook_pb2
    
    p = addressbook_pb2.Person()
    p.name = "Freddie"
    p.email = "[email protected]"
    
    print(p)
    

    You can generate a PYI file for the generated code too using --pyi_out=${PWD}