@@ -159,10 +159,11 @@ def dataclass_field(
159
159
map_types : Optional [Tuple [str , str ]] = None ,
160
160
group : Optional [str ] = None ,
161
161
wraps : Optional [str ] = None ,
162
+ optional : bool = False ,
162
163
) -> dataclasses .Field :
163
164
"""Creates a dataclass field with attached protobuf metadata."""
164
165
return dataclasses .field (
165
- default = PLACEHOLDER ,
166
+ default = None if optional else PLACEHOLDER ,
166
167
metadata = {
167
168
"betterproto" : FieldMetadata (number , proto_type , map_types , group , wraps )
168
169
},
@@ -174,74 +175,74 @@ def dataclass_field(
174
175
# out at runtime. The generated dataclass variables are still typed correctly.
175
176
176
177
177
- def enum_field (number : int , group : Optional [str ] = None ) -> Any :
178
- return dataclass_field (number , TYPE_ENUM , group = group )
178
+ def enum_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
179
+ return dataclass_field (number , TYPE_ENUM , group = group , optional = optional )
179
180
180
181
181
- def bool_field (number : int , group : Optional [str ] = None ) -> Any :
182
- return dataclass_field (number , TYPE_BOOL , group = group )
182
+ def bool_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
183
+ return dataclass_field (number , TYPE_BOOL , group = group , optional = optional )
183
184
184
185
185
- def int32_field (number : int , group : Optional [str ] = None ) -> Any :
186
- return dataclass_field (number , TYPE_INT32 , group = group )
186
+ def int32_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
187
+ return dataclass_field (number , TYPE_INT32 , group = group , optional = optional )
187
188
188
189
189
- def int64_field (number : int , group : Optional [str ] = None ) -> Any :
190
- return dataclass_field (number , TYPE_INT64 , group = group )
190
+ def int64_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
191
+ return dataclass_field (number , TYPE_INT64 , group = group , optional = optional )
191
192
192
193
193
- def uint32_field (number : int , group : Optional [str ] = None ) -> Any :
194
- return dataclass_field (number , TYPE_UINT32 , group = group )
194
+ def uint32_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
195
+ return dataclass_field (number , TYPE_UINT32 , group = group , optional = optional )
195
196
196
197
197
- def uint64_field (number : int , group : Optional [str ] = None ) -> Any :
198
- return dataclass_field (number , TYPE_UINT64 , group = group )
198
+ def uint64_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
199
+ return dataclass_field (number , TYPE_UINT64 , group = group , optional = optional )
199
200
200
201
201
- def sint32_field (number : int , group : Optional [str ] = None ) -> Any :
202
- return dataclass_field (number , TYPE_SINT32 , group = group )
202
+ def sint32_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
203
+ return dataclass_field (number , TYPE_SINT32 , group = group , optional = optional )
203
204
204
205
205
- def sint64_field (number : int , group : Optional [str ] = None ) -> Any :
206
- return dataclass_field (number , TYPE_SINT64 , group = group )
206
+ def sint64_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
207
+ return dataclass_field (number , TYPE_SINT64 , group = group , optional = optional )
207
208
208
209
209
- def float_field (number : int , group : Optional [str ] = None ) -> Any :
210
- return dataclass_field (number , TYPE_FLOAT , group = group )
210
+ def float_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
211
+ return dataclass_field (number , TYPE_FLOAT , group = group , optional = optional )
211
212
212
213
213
- def double_field (number : int , group : Optional [str ] = None ) -> Any :
214
- return dataclass_field (number , TYPE_DOUBLE , group = group )
214
+ def double_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
215
+ return dataclass_field (number , TYPE_DOUBLE , group = group , optional = optional )
215
216
216
217
217
- def fixed32_field (number : int , group : Optional [str ] = None ) -> Any :
218
- return dataclass_field (number , TYPE_FIXED32 , group = group )
218
+ def fixed32_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
219
+ return dataclass_field (number , TYPE_FIXED32 , group = group , optional = optional )
219
220
220
221
221
- def fixed64_field (number : int , group : Optional [str ] = None ) -> Any :
222
- return dataclass_field (number , TYPE_FIXED64 , group = group )
222
+ def fixed64_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
223
+ return dataclass_field (number , TYPE_FIXED64 , group = group , optional = optional )
223
224
224
225
225
- def sfixed32_field (number : int , group : Optional [str ] = None ) -> Any :
226
- return dataclass_field (number , TYPE_SFIXED32 , group = group )
226
+ def sfixed32_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
227
+ return dataclass_field (number , TYPE_SFIXED32 , group = group , optional = optional )
227
228
228
229
229
- def sfixed64_field (number : int , group : Optional [str ] = None ) -> Any :
230
- return dataclass_field (number , TYPE_SFIXED64 , group = group )
230
+ def sfixed64_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
231
+ return dataclass_field (number , TYPE_SFIXED64 , group = group , optional = optional )
231
232
232
233
233
- def string_field (number : int , group : Optional [str ] = None ) -> Any :
234
- return dataclass_field (number , TYPE_STRING , group = group )
234
+ def string_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
235
+ return dataclass_field (number , TYPE_STRING , group = group , optional = optional )
235
236
236
237
237
- def bytes_field (number : int , group : Optional [str ] = None ) -> Any :
238
- return dataclass_field (number , TYPE_BYTES , group = group )
238
+ def bytes_field (number : int , group : Optional [str ] = None , optional : bool = False ) -> Any :
239
+ return dataclass_field (number , TYPE_BYTES , group = group , optional = optional )
239
240
240
241
241
242
def message_field (
242
- number : int , group : Optional [str ] = None , wraps : Optional [str ] = None
243
+ number : int , group : Optional [str ] = None , wraps : Optional [str ] = None , optional : bool = False
243
244
) -> Any :
244
- return dataclass_field (number , TYPE_MESSAGE , group = group , wraps = wraps )
245
+ return dataclass_field (number , TYPE_MESSAGE , group = group , wraps = wraps , optional = optional )
245
246
246
247
247
248
def map_field (
@@ -701,12 +702,16 @@ def __bytes__(self) -> bytes:
701
702
702
703
if value is None :
703
704
# Optional items should be skipped. This is used for the Google
704
- # wrapper types.
705
+ # wrapper types and proto3 field presence/optional fields .
705
706
continue
706
707
707
708
# Being selected in a a group means this field is the one that is
708
709
# currently set in a `oneof` group, so it must be serialized even
709
710
# if the value is the default zero value.
711
+ #
712
+ # Note that proto3 field presence/optional fields are put in a
713
+ # synthetic single-item oneof by protoc, which helps us ensure we
714
+ # send the value even if the value is the default zero value.
710
715
selected_in_group = (
711
716
meta .group and self ._group_current [meta .group ] == field_name
712
717
)
0 commit comments