Reflection
protobuf-py exposes the full Protobuf descriptor model at runtime. Descriptors are the single source of truth for every message and enum: they describe the schema, and all serialization, presence tracking, and field access are driven through them.
Descriptor types
Descriptors wrap the compiler's internal descriptor messages and give them a convenient Python API.
Their names all start with Desc:
| Type | Wraps | Purpose |
|---|---|---|
DescFile |
FileDescriptorProto |
A single .proto source file. Root of the hierarchy. |
DescMessage |
DescriptorProto |
A message declaration. |
DescField |
FieldDescriptorProto |
A field declared in a message. |
DescOneof |
OneofDescriptorProto |
A oneof group in a message. |
DescEnum |
EnumDescriptorProto |
An enum declaration. |
DescEnumValue |
EnumValueDescriptorProto |
A single enum value. |
DescExtension |
FieldDescriptorProto |
An extension field defined outside its container message. |
DescService |
ServiceDescriptorProto |
An RPC service. |
DescMethod |
MethodDescriptorProto |
A single RPC method. |
Descriptors form a hierarchy rooted at a file:
DescFile
├─ messages: DescMessage
│ ├─ fields: DescField
│ ├─ oneofs: DescOneof
│ ├─ members: DescField | DescOneof (fields + oneofs in source order)
│ ├─ nested_messages: DescMessage
│ ├─ nested_enums: DescEnum
│ └─ nested_extensions: DescExtension
├─ enums: DescEnum
│ └─ values: DescEnumValue
├─ extensions: DescExtension
└─ services: DescService
└─ methods: DescMethod
Getting a descriptor
Every generated class carries its descriptor.
Use Message.desc() to retrieve it:
from gen.example_pb import User
desc = User.desc() # DescMessage
desc.name # "User"
desc.type_name # "example.User"
The file-level descriptor is exported as a getter function from the generated _pb.py:
from gen import example_pb
example_pb.desc().name # "example.proto"
example_pb.desc().messages # [DescMessage, ...]
Next steps
- Descriptors: walking through a schema, field descriptors, enums
- Registry: looking up types by name
- Dynamic Messaging: instantiating messages from runtime-loaded schemas
- Custom options: reading annotations from proto files