0
# Field System
1
2
The Field system provides the building blocks for defining message structure in proto-plus. Fields define the data members of protocol buffer messages, handling type validation, serialization, and providing the mapping between Python attributes and protocol buffer fields.
3
4
## Capabilities
5
6
### Basic Field Definition
7
8
Define individual fields within protocol buffer messages using the Field class.
9
10
```python { .api }
11
class Field:
12
"""
13
A representation of a type of field in protocol buffers.
14
15
Args:
16
proto_type: The protocol buffer type (ProtoType enum value or message/enum class)
17
number (int): The field number in the protocol buffer definition
18
message: Message class for MESSAGE type fields
19
enum: Enum class for ENUM type fields
20
oneof (str): Name of oneof group this field belongs to
21
json_name (str): Custom JSON field name
22
optional (bool): Whether this is an optional field (proto3)
23
"""
24
def __init__(self, proto_type, *, number: int, message=None, enum=None,
25
oneof: str = None, json_name: str = None, optional: bool = False): ...
26
27
@property
28
def name(self) -> str:
29
"""Return the name of the field."""
30
31
@property
32
def package(self) -> str:
33
"""Return the package of the field."""
34
35
@property
36
def pb_type(self):
37
"""Return the composite type of the field, or the primitive type if a primitive."""
38
39
@property
40
def descriptor(self):
41
"""Return the descriptor for the field."""
42
```
43
44
Example usage:
45
46
```python
47
class Product(proto.Message):
48
# Primitive fields
49
name = proto.Field(proto.STRING, number=1)
50
price = proto.Field(proto.FLOAT, number=2)
51
in_stock = proto.Field(proto.BOOL, number=3)
52
53
# Optional field
54
description = proto.Field(proto.STRING, number=4, optional=True)
55
56
# Custom JSON name
57
product_id = proto.Field(proto.STRING, number=5, json_name="productId")
58
59
# Message field
60
category = proto.Field(Category, number=6)
61
62
# Enum field
63
status = proto.Field(ProductStatus, number=7)
64
```
65
66
### Repeated Fields
67
68
Define fields that can contain multiple values using RepeatedField.
69
70
```python { .api }
71
class RepeatedField(Field):
72
"""
73
A representation of a repeated field in protocol buffers.
74
75
Inherits all parameters from Field. The resulting field will contain
76
a sequence of values of the specified type.
77
"""
78
```
79
80
Example usage:
81
82
```python
83
class Order(proto.Message):
84
# Repeated primitive fields
85
item_ids = proto.RepeatedField(proto.STRING, number=1)
86
quantities = proto.RepeatedField(proto.INT32, number=2)
87
88
# Repeated message fields
89
line_items = proto.RepeatedField(LineItem, number=3)
90
91
# Repeated enum fields
92
statuses = proto.RepeatedField(OrderStatus, number=4)
93
94
# Usage
95
order = Order(
96
item_ids=["item1", "item2", "item3"],
97
quantities=[1, 2, 1],
98
line_items=[
99
LineItem(name="Widget", price=10.0),
100
LineItem(name="Gadget", price=25.0)
101
]
102
)
103
104
# Access like Python lists
105
print(len(order.item_ids)) # 3
106
order.item_ids.append("item4")
107
for item_id in order.item_ids:
108
print(item_id)
109
```
110
111
### Map Fields
112
113
Define key-value mapping fields using MapField.
114
115
```python { .api }
116
class MapField(Field):
117
"""
118
A representation of a map field in protocol buffers.
119
120
Args:
121
key_type: The protocol buffer type for map keys
122
value_type: The protocol buffer type for map values
123
number (int): The field number in the protocol buffer definition
124
message: Message class for MESSAGE type values
125
enum: Enum class for ENUM type values
126
"""
127
def __init__(self, key_type, value_type, *, number: int, message=None, enum=None): ...
128
```
129
130
Example usage:
131
132
```python
133
class Configuration(proto.Message):
134
# String to string map
135
settings = proto.MapField(proto.STRING, proto.STRING, number=1)
136
137
# String to integer map
138
limits = proto.MapField(proto.STRING, proto.INT32, number=2)
139
140
# String to message map
141
services = proto.MapField(proto.STRING, ServiceConfig, number=3)
142
143
# String to enum map
144
permissions = proto.MapField(proto.STRING, PermissionLevel, number=4)
145
146
# Usage
147
config = Configuration(
148
settings={
149
"debug": "true",
150
"log_level": "info"
151
},
152
limits={
153
"max_connections": 100,
154
"timeout_seconds": 30
155
}
156
)
157
158
# Access like Python dictionaries
159
print(config.settings["debug"]) # "true"
160
config.settings["new_setting"] = "value"
161
for key, value in config.limits.items():
162
print(f"{key}: {value}")
163
```
164
165
## Field Types and Protocol Buffer Integration
166
167
### Primitive Types
168
169
All protocol buffer primitive types are supported:
170
171
```python
172
# Numeric types
173
age = proto.Field(proto.INT32, number=1)
174
balance = proto.Field(proto.FLOAT, number=2)
175
precise_value = proto.Field(proto.DOUBLE, number=3)
176
user_id = proto.Field(proto.UINT64, number=4)
177
178
# String and bytes
179
name = proto.Field(proto.STRING, number=5)
180
data = proto.Field(proto.BYTES, number=6)
181
182
# Boolean
183
is_active = proto.Field(proto.BOOL, number=7)
184
```
185
186
### Message Types
187
188
Reference other proto-plus messages:
189
190
```python
191
class Address(proto.Message):
192
street = proto.Field(proto.STRING, number=1)
193
city = proto.Field(proto.STRING, number=2)
194
195
class Person(proto.Message):
196
name = proto.Field(proto.STRING, number=1)
197
# Message field - reference another message type
198
address = proto.Field(Address, number=2)
199
```
200
201
### Enum Types
202
203
Reference proto-plus enums:
204
205
```python
206
class Priority(proto.Enum):
207
LOW = 1
208
MEDIUM = 2
209
HIGH = 3
210
211
class Task(proto.Message):
212
title = proto.Field(proto.STRING, number=1)
213
# Enum field - reference an enum type
214
priority = proto.Field(Priority, number=2)
215
```
216
217
### Oneof Fields
218
219
Group fields into oneof constructs where only one field can be set:
220
221
```python
222
class Contact(proto.Message):
223
name = proto.Field(proto.STRING, number=1)
224
225
# Oneof group - only one of these can be set
226
email = proto.Field(proto.STRING, number=2, oneof="contact_method")
227
phone = proto.Field(proto.STRING, number=3, oneof="contact_method")
228
address = proto.Field(Address, number=4, oneof="contact_method")
229
230
# Usage
231
contact = Contact(name="John", email="john@example.com")
232
# contact.phone would be unset since email is set in the same oneof
233
```
234
235
### Optional Fields
236
237
Mark fields as optional in proto3:
238
239
```python
240
class User(proto.Message):
241
# Required fields (will have default values if not set)
242
username = proto.Field(proto.STRING, number=1)
243
244
# Optional field (can distinguish between unset and default value)
245
middle_name = proto.Field(proto.STRING, number=2, optional=True)
246
age = proto.Field(proto.INT32, number=3, optional=True)
247
248
# Usage
249
user = User(username="alice")
250
print("middle_name" in user) # False - not set
251
print("username" in user) # True - set
252
253
user.middle_name = ""
254
print("middle_name" in user) # True - set to empty string
255
```
256
257
## Advanced Field Features
258
259
### JSON Field Names
260
261
Customize JSON serialization field names:
262
263
```python
264
class Product(proto.Message):
265
internal_id = proto.Field(proto.STRING, number=1, json_name="productId")
266
display_name = proto.Field(proto.STRING, number=2, json_name="displayName")
267
268
# JSON will use "productId" and "displayName" instead of "internal_id" and "display_name"
269
```
270
271
### Field Validation and Conversion
272
273
Fields automatically handle type validation and conversion:
274
275
```python
276
class Stats(proto.Message):
277
count = proto.Field(proto.INT32, number=1)
278
279
# Automatic conversion
280
stats = Stats(count="123") # String converted to int
281
print(stats.count) # 123 (integer)
282
283
# Type validation
284
try:
285
stats = Stats(count="invalid") # Raises error
286
except ValueError:
287
print("Invalid value")
288
```