0
# Module System
1
2
The Module system provides organization and management utilities for protocol buffer definitions across multiple files and packages. It enables structured organization of proto-plus messages and enums within logical modules while managing protocol buffer file generation and package hierarchies.
3
4
## Capabilities
5
6
### Module Definition
7
8
Define protocol buffer modules with specific package organization and marshal management.
9
10
```python { .api }
11
def define_module(*, package: str, marshal: str = None,
12
manifest: Set[str] = frozenset()) -> _ProtoModule:
13
"""
14
Define a protocol buffers module.
15
16
The settings defined here are used for all protobuf messages
17
declared in the module of the given name.
18
19
Args:
20
package (str): The proto package name.
21
marshal (str): The name of the marshal to use. It is recommended
22
to use one marshal per Python library (e.g. package on PyPI).
23
If not provided, defaults to the package name.
24
manifest (Set[str]): A set of messages and enums to be created. Setting
25
this adds a slight efficiency in piecing together proto
26
descriptors under the hood.
27
28
Returns:
29
_ProtoModule: A named tuple containing package, marshal, and manifest settings.
30
"""
31
```
32
33
The function is exported as `module` in the main proto package:
34
35
```python
36
import proto
37
38
# Access the function as proto.module
39
my_module = proto.module(package="com.example.api", marshal="example_api")
40
```
41
42
Example usage:
43
44
```python
45
import proto
46
47
# Define a module for an API package
48
api_module = proto.module(
49
package="com.example.api",
50
marshal="example_api",
51
manifest={"User", "Order", "Product", "OrderStatus"}
52
)
53
54
# Define a module for internal services
55
internal_module = proto.module(
56
package="com.example.internal",
57
marshal="internal_services"
58
)
59
60
# Simple module definition (marshal defaults to package name)
61
simple_module = proto.module(package="com.example.simple")
62
```
63
64
### Module Integration with Messages
65
66
Use defined modules in message and enum definitions by setting the module attribute:
67
68
```python
69
import proto
70
71
# Define the module
72
api_module = proto.module(
73
package="com.example.api",
74
marshal="api_marshal"
75
)
76
77
# Use the module in message definitions
78
class User(proto.Message):
79
__module__ = api_module
80
81
user_id = proto.Field(proto.STRING, number=1)
82
email = proto.Field(proto.STRING, number=2)
83
created_at = proto.Field(proto.INT64, number=3)
84
85
class Order(proto.Message):
86
__module__ = api_module
87
88
order_id = proto.Field(proto.STRING, number=1)
89
user = proto.Field(User, number=2)
90
total = proto.Field(proto.FLOAT, number=3)
91
92
class OrderStatus(proto.Enum):
93
__module__ = api_module
94
95
PENDING = 0
96
CONFIRMED = 1
97
SHIPPED = 2
98
DELIVERED = 3
99
```
100
101
### Package Organization
102
103
Organize messages into logical package hierarchies:
104
105
```python
106
import proto
107
108
# Core API types
109
core_module = proto.module(package="com.example.core")
110
111
class BaseEntity(proto.Message):
112
__module__ = core_module
113
114
id = proto.Field(proto.STRING, number=1)
115
created_at = proto.Field(proto.INT64, number=2)
116
updated_at = proto.Field(proto.INT64, number=3)
117
118
# User management API
119
user_module = proto.module(package="com.example.user")
120
121
class User(proto.Message):
122
__module__ = user_module
123
124
base = proto.Field(BaseEntity, number=1)
125
username = proto.Field(proto.STRING, number=2)
126
email = proto.Field(proto.STRING, number=3)
127
128
# Order management API
129
order_module = proto.module(package="com.example.order")
130
131
class Order(proto.Message):
132
__module__ = order_module
133
134
base = proto.Field(BaseEntity, number=1)
135
user_id = proto.Field(proto.STRING, number=2)
136
items = proto.RepeatedField(OrderItem, number=3)
137
```
138
139
### Marshal Management
140
141
Control marshal instances across modules for shared type conversion:
142
143
```python
144
import proto
145
146
# Shared marshal for the entire application
147
app_marshal = "my_application"
148
149
# All modules use the same marshal
150
user_module = proto.module(
151
package="com.myapp.user",
152
marshal=app_marshal
153
)
154
155
order_module = proto.module(
156
package="com.myapp.order",
157
marshal=app_marshal
158
)
159
160
inventory_module = proto.module(
161
package="com.myapp.inventory",
162
marshal=app_marshal
163
)
164
165
# Messages in different modules share type conversion rules
166
class User(proto.Message):
167
__module__ = user_module
168
# ... fields ...
169
170
class Order(proto.Message):
171
__module__ = order_module
172
user = proto.Field(User, number=1) # Cross-module reference
173
# ... other fields ...
174
```
175
176
### Manifest Optimization
177
178
Use manifests to optimize protocol buffer descriptor generation:
179
180
```python
181
import proto
182
183
# Define module with manifest for better performance
184
api_module = proto.module(
185
package="com.example.api",
186
marshal="api",
187
manifest={
188
# Messages
189
"User", "Order", "Product", "Category",
190
"Address", "PaymentMethod",
191
192
# Enums
193
"UserStatus", "OrderStatus", "ProductType",
194
"PaymentType"
195
}
196
)
197
198
# Define the messages and enums listed in manifest
199
class User(proto.Message):
200
__module__ = api_module
201
# ... fields ...
202
203
class UserStatus(proto.Enum):
204
__module__ = api_module
205
# ... values ...
206
207
# All other messages and enums follow...
208
```
209
210
### Cross-Module References
211
212
Reference messages and enums across different modules:
213
214
```python
215
import proto
216
217
# Define modules
218
common_module = proto.module(package="com.example.common")
219
user_module = proto.module(package="com.example.user")
220
order_module = proto.module(package="com.example.order")
221
222
# Common types
223
class Address(proto.Message):
224
__module__ = common_module
225
226
street = proto.Field(proto.STRING, number=1)
227
city = proto.Field(proto.STRING, number=2)
228
postal_code = proto.Field(proto.STRING, number=3)
229
230
class Currency(proto.Enum):
231
__module__ = common_module
232
233
USD = 1
234
EUR = 2
235
GBP = 3
236
237
# User module references common types
238
class User(proto.Message):
239
__module__ = user_module
240
241
name = proto.Field(proto.STRING, number=1)
242
billing_address = proto.Field(Address, number=2) # Cross-module reference
243
244
# Order module references both common and user types
245
class Order(proto.Message):
246
__module__ = order_module
247
248
order_id = proto.Field(proto.STRING, number=1)
249
user = proto.Field(User, number=2) # Cross-module reference
250
currency = proto.Field(Currency, number=3) # Cross-module reference
251
shipping_address = proto.Field(Address, number=4) # Cross-module reference
252
```
253
254
## Module System Features
255
256
### Automatic File Organization
257
258
The module system automatically organizes protocol buffer definitions into appropriate file structures:
259
260
```python
261
# Messages with the same module are grouped together
262
# in the generated protocol buffer files
263
264
core_module = proto.module(package="com.example.core")
265
266
# These messages will be in the same proto file
267
class Entity(proto.Message):
268
__module__ = core_module
269
# ...
270
271
class Metadata(proto.Message):
272
__module__ = core_module
273
# ...
274
275
class Status(proto.Enum):
276
__module__ = core_module
277
# ...
278
```
279
280
### Package Namespacing
281
282
Modules provide proper protocol buffer package namespacing:
283
284
```python
285
# Different modules create separate protocol buffer packages
286
auth_module = proto.module(package="com.myapp.auth")
287
data_module = proto.module(package="com.myapp.data")
288
289
# These create different protobuf packages:
290
# com.myapp.auth.User vs com.myapp.data.User
291
class User(proto.Message): # auth user
292
__module__ = auth_module
293
username = proto.Field(proto.STRING, number=1)
294
295
class User(proto.Message): # data user
296
__module__ = data_module
297
profile_data = proto.Field(proto.BYTES, number=1)
298
```
299
300
### Import Management
301
302
The module system handles protocol buffer imports automatically:
303
304
```python
305
base_module = proto.module(package="com.example.base")
306
extended_module = proto.module(package="com.example.extended")
307
308
class BaseMessage(proto.Message):
309
__module__ = base_module
310
id = proto.Field(proto.STRING, number=1)
311
312
class ExtendedMessage(proto.Message):
313
__module__ = extended_module
314
base = proto.Field(BaseMessage, number=1) # Automatic import handling
315
extra_data = proto.Field(proto.STRING, number=2)
316
```
317
318
### Module Information Access
319
320
Access module configuration information:
321
322
```python
323
import proto
324
325
# Create module
326
my_module = proto.module(
327
package="com.example.test",
328
marshal="test_marshal",
329
manifest={"TestMessage"}
330
)
331
332
# Access module properties
333
print(my_module.package) # "com.example.test"
334
print(my_module.marshal) # "test_marshal"
335
print(my_module.manifest) # frozenset({"TestMessage"})
336
```