@@ -169,24 +169,6 @@ class Casing(builtin_enum.Enum):
169
169
SNAKE = snake_case #: A snake_case sterilization function.
170
170
171
171
172
- class Placeholder :
173
- __slots__ = ()
174
-
175
- def __repr__ (self ) -> str :
176
- return "<PLACEHOLDER>"
177
-
178
- def __copy__ (self ) -> Self :
179
- return self
180
-
181
- def __deepcopy__ (self , _ ) -> Self :
182
- return self
183
-
184
-
185
- # We can't simply use object() here because pydantic automatically performs deep-copy of mutable default values
186
- # See #606
187
- PLACEHOLDER : Any = Placeholder ()
188
-
189
-
190
172
@dataclasses .dataclass (frozen = True )
191
173
class FieldMetadata :
192
174
"""Stores internal metadata used for parsing & serialization."""
@@ -213,6 +195,7 @@ def get(field: dataclasses.Field) -> "FieldMetadata":
213
195
def dataclass_field (
214
196
number : int ,
215
197
proto_type : str ,
198
+ default_factory : Callable [[], Any ],
216
199
* ,
217
200
map_types : Optional [Tuple [str , str ]] = None ,
218
201
group : Optional [str ] = None ,
@@ -221,8 +204,15 @@ def dataclass_field(
221
204
repeated : bool = False ,
222
205
) -> dataclasses .Field :
223
206
"""Creates a dataclass field with attached protobuf metadata."""
207
+ if optional :
208
+ def default_factory ():
209
+ return None
210
+ elif repeated :
211
+ def default_factory ():
212
+ return []
213
+
224
214
return dataclasses .field (
225
- default = None if optional else PLACEHOLDER , # type: ignore
215
+ default_factory = default_factory ,
226
216
metadata = {
227
217
"betterproto" : FieldMetadata (
228
218
number , proto_type , map_types , group , wraps , optional
@@ -236,96 +226,96 @@ def dataclass_field(
236
226
# out at runtime. The generated dataclass variables are still typed correctly.
237
227
238
228
239
- def enum_field (number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False , ) -> Any :
240
- return dataclass_field (number , TYPE_ENUM , group = group , optional = optional , repeated = repeated )
229
+ def enum_field (number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ) -> Any :
230
+ return dataclass_field (number , TYPE_ENUM , lambda : 0 , optional = optional , repeated = repeated )
241
231
242
232
243
- def bool_field (number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False , ) -> Any :
244
- return dataclass_field (number , TYPE_BOOL , group = group , optional = optional , repeated = repeated )
233
+ def bool_field (number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ) -> Any :
234
+ return dataclass_field (number , TYPE_BOOL , lambda : False , group = group , optional = optional , repeated = repeated )
245
235
246
236
247
237
def int32_field (
248
238
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
249
239
) -> Any :
250
- return dataclass_field (number , TYPE_INT32 , group = group , optional = optional , repeated = repeated )
240
+ return dataclass_field (number , TYPE_INT32 , lambda : 0 , group = group , optional = optional , repeated = repeated )
251
241
252
242
253
243
def int64_field (
254
244
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
255
245
) -> Any :
256
- return dataclass_field (number , TYPE_INT64 , group = group , optional = optional , repeated = repeated )
246
+ return dataclass_field (number , TYPE_INT64 , lambda : 0 , group = group , optional = optional , repeated = repeated )
257
247
258
248
259
249
def uint32_field (
260
250
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
261
251
) -> Any :
262
- return dataclass_field (number , TYPE_UINT32 , group = group , optional = optional , repeated = repeated )
252
+ return dataclass_field (number , TYPE_UINT32 , lambda : 0 , group = group , optional = optional , repeated = repeated )
263
253
264
254
265
255
def uint64_field (
266
256
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
267
257
) -> Any :
268
- return dataclass_field (number , TYPE_UINT64 , group = group , optional = optional , repeated = repeated )
258
+ return dataclass_field (number , TYPE_UINT64 , lambda : 0 , group = group , optional = optional , repeated = repeated )
269
259
270
260
271
261
def sint32_field (
272
262
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
273
263
) -> Any :
274
- return dataclass_field (number , TYPE_SINT32 , group = group , optional = optional , repeated = repeated )
264
+ return dataclass_field (number , TYPE_SINT32 , lambda : 0 , group = group , optional = optional , repeated = repeated )
275
265
276
266
277
267
def sint64_field (
278
268
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
279
269
) -> Any :
280
- return dataclass_field (number , TYPE_SINT64 , group = group , optional = optional , repeated = repeated )
270
+ return dataclass_field (number , TYPE_SINT64 , lambda : 0 , group = group , optional = optional , repeated = repeated )
281
271
282
272
283
273
def float_field (
284
274
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
285
275
) -> Any :
286
- return dataclass_field (number , TYPE_FLOAT , group = group , optional = optional , repeated = repeated )
276
+ return dataclass_field (number , TYPE_FLOAT , lambda : 0. , group = group , optional = optional , repeated = repeated )
287
277
288
278
289
279
def double_field (
290
280
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
291
281
) -> Any :
292
- return dataclass_field (number , TYPE_DOUBLE , group = group , optional = optional , repeated = repeated )
282
+ return dataclass_field (number , TYPE_DOUBLE , lambda : 0. , group = group , optional = optional , repeated = repeated )
293
283
294
284
295
285
def fixed32_field (
296
286
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
297
287
) -> Any :
298
- return dataclass_field (number , TYPE_FIXED32 , group = group , optional = optional , repeated = repeated )
288
+ return dataclass_field (number , TYPE_FIXED32 , lambda : 0. , group = group , optional = optional , repeated = repeated )
299
289
300
290
301
291
def fixed64_field (
302
292
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
303
293
) -> Any :
304
- return dataclass_field (number , TYPE_FIXED64 , group = group , optional = optional , repeated = repeated )
294
+ return dataclass_field (number , TYPE_FIXED64 , lambda : 0. , group = group , optional = optional , repeated = repeated )
305
295
306
296
307
297
def sfixed32_field (
308
298
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
309
299
) -> Any :
310
- return dataclass_field (number , TYPE_SFIXED32 , group = group , optional = optional , repeated = repeated )
300
+ return dataclass_field (number , TYPE_SFIXED32 , lambda : 0. , group = group , optional = optional , repeated = repeated )
311
301
312
302
313
303
def sfixed64_field (
314
304
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
315
305
) -> Any :
316
- return dataclass_field (number , TYPE_SFIXED64 , group = group , optional = optional , repeated = repeated )
306
+ return dataclass_field (number , TYPE_SFIXED64 , lambda : 0. , group = group , optional = optional , repeated = repeated )
317
307
318
308
319
309
def string_field (
320
310
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
321
311
) -> Any :
322
- return dataclass_field (number , TYPE_STRING , group = group , optional = optional , repeated = repeated )
312
+ return dataclass_field (number , TYPE_STRING , lambda : "" , group = group , optional = optional , repeated = repeated )
323
313
324
314
325
315
def bytes_field (
326
316
number : int , group : Optional [str ] = None , optional : bool = False , repeated : bool = False ,
327
317
) -> Any :
328
- return dataclass_field (number , TYPE_BYTES , group = group , optional = optional , repeated = repeated )
318
+ return dataclass_field (number , TYPE_BYTES , lambda : b"" , group = group , optional = optional , repeated = repeated )
329
319
330
320
331
321
def message_field (
@@ -336,15 +326,15 @@ def message_field(
336
326
repeated : bool = False ,
337
327
) -> Any :
338
328
return dataclass_field (
339
- number , TYPE_MESSAGE , group = group , wraps = wraps , optional = optional
329
+ number , TYPE_MESSAGE , lambda : None , group = group , wraps = wraps , optional = optional , repeated = repeated
340
330
)
341
331
342
332
343
333
def map_field (
344
334
number : int , key_type : str , value_type : str , group : Optional [str ] = None
345
335
) -> Any :
346
336
return dataclass_field (
347
- number , TYPE_MAP , map_types = (key_type , value_type ), group = group
337
+ number , TYPE_MAP , lambda : dict (), map_types = (key_type , value_type ), group = group
348
338
)
349
339
350
340
@@ -729,8 +719,8 @@ def _get_cls_by_field(
729
719
field_cls [field .name ] = dataclasses .make_dataclass (
730
720
"Entry" ,
731
721
[
732
- ("key" , kt , dataclass_field (1 , meta .map_types [0 ])),
733
- ("value" , vt , dataclass_field (2 , meta .map_types [1 ])),
722
+ ("key" , kt , dataclass_field (1 , meta .map_types [0 ], default_factory = lambda : kt () )),
723
+ ("value" , vt , dataclass_field (2 , meta .map_types [1 ], default_factory = lambda : vt () )),
734
724
],
735
725
bases = (Message ,),
736
726
)
@@ -764,26 +754,27 @@ class Message(ABC):
764
754
_betterproto_meta : ClassVar [ProtoClassMetadata ]
765
755
766
756
def __post_init__ (self ) -> None :
767
- # Keep track of whether every field was default
768
- all_sentinel = True
757
+ # # Keep track of whether every field was default
758
+ # all_sentinel = True
769
759
770
760
# Set current field of each group after `__init__` has already been run.
771
761
group_current : Dict [str , Optional [str ]] = {}
772
762
for field_name , meta in self ._betterproto .meta_by_field_name .items ():
773
763
if meta .group :
774
764
group_current .setdefault (meta .group )
775
765
776
- value = self .__raw_get (field_name )
777
- if value is not PLACEHOLDER and not (meta .optional and value is None ):
778
- # Found a non-sentinel value
779
- all_sentinel = False
766
+ # value = self.__raw_get(field_name)
767
+ # if value is not PLACEHOLDER and not (meta.optional and value is None):
768
+ # # Found a non-sentinel value
769
+ # all_sentinel = False
780
770
781
- if meta .group :
782
- # This was set, so make it the selected value of the one-of.
783
- group_current [meta .group ] = field_name
771
+ # if meta.group:
772
+ # # This was set, so make it the selected value of the one-of.
773
+ # group_current[meta.group] = field_name
784
774
785
775
# Now that all the defaults are set, reset it!
786
- self .__dict__ ["_serialized_on_wire" ] = not all_sentinel
776
+ # self.__dict__["_serialized_on_wire"] = not all_sentinel
777
+ self .__dict__ ["_serialized_on_wire" ] = False
787
778
self .__dict__ ["_unknown_fields" ] = b""
788
779
self .__dict__ ["_group_current" ] = group_current
789
780
@@ -797,12 +788,6 @@ def __eq__(self, other) -> bool:
797
788
for field_name in self ._betterproto .meta_by_field_name :
798
789
self_val = self .__raw_get (field_name )
799
790
other_val = other .__raw_get (field_name )
800
- if self_val is PLACEHOLDER :
801
- if other_val is PLACEHOLDER :
802
- continue
803
- self_val = self ._get_field_default (field_name )
804
- elif other_val is PLACEHOLDER :
805
- other_val = other ._get_field_default (field_name )
806
791
807
792
if self_val != other_val :
808
793
# We consider two nan values to be the same for the
@@ -825,48 +810,12 @@ def __repr__(self) -> str:
825
810
f"{ field_name } ={ value !r} "
826
811
for field_name in self ._betterproto .sorted_field_names
827
812
for value in (self .__raw_get (field_name ),)
828
- if value is not PLACEHOLDER
829
813
]
830
814
return f"{ self .__class__ .__name__ } ({ ', ' .join (parts )} )"
831
815
832
- def __rich_repr__ (self ) -> Iterable [Tuple [str , Any , Any ]]:
833
- for field_name in self ._betterproto .sorted_field_names :
834
- yield field_name , self .__raw_get (field_name ), PLACEHOLDER
835
-
836
- if not TYPE_CHECKING :
837
-
838
- def __getattribute__ (self , name : str ) -> Any :
839
- """
840
- Lazily initialize default values to avoid infinite recursion for recursive
841
- message types.
842
- Raise :class:`AttributeError` on attempts to access unset ``oneof`` fields.
843
- """
844
- try :
845
- group_current = super ().__getattribute__ ("_group_current" )
846
- except AttributeError :
847
- pass
848
- else :
849
- if name not in {"__class__" , "_betterproto" }:
850
- group = self ._betterproto .oneof_group_by_field .get (name )
851
- if group is not None and group_current [group ] != name :
852
- if sys .version_info < (3 , 10 ):
853
- raise AttributeError (
854
- f"{ group !r} is set to { group_current [group ]!r} , not { name !r} "
855
- )
856
- else :
857
- raise AttributeError (
858
- f"{ group !r} is set to { group_current [group ]!r} , not { name !r} " ,
859
- name = name ,
860
- obj = self ,
861
- )
862
-
863
- value = super ().__getattribute__ (name )
864
- if value is not PLACEHOLDER :
865
- return value
866
-
867
- value = self ._get_field_default (name )
868
- super ().__setattr__ (name , value )
869
- return value
816
+ # def __rich_repr__(self) -> Iterable[Tuple[str, Any, Any]]:
817
+ # for field_name in self._betterproto.sorted_field_names:
818
+ # yield field_name, self.__raw_get(field_name), PLACEHOLDER
870
819
871
820
def __setattr__ (self , attr : str , value : Any ) -> None :
872
821
if (
@@ -887,32 +836,29 @@ def __setattr__(self, attr: str, value: Any) -> None:
887
836
if field .name == attr :
888
837
self ._group_current [group ] = field .name
889
838
else :
890
- super ().__setattr__ (field .name , PLACEHOLDER )
839
+ super ().__setattr__ (field .name , None )
891
840
892
841
super ().__setattr__ (attr , value )
893
842
894
843
def __bool__ (self ) -> bool :
895
844
"""True if the Message has any fields with non-default values."""
896
845
return any (
897
- self .__raw_get (field_name )
898
- not in (PLACEHOLDER , self ._get_field_default (field_name ))
846
+ self .__raw_get (field_name ) != self ._get_field_default (field_name )
899
847
for field_name in self ._betterproto .meta_by_field_name
900
848
)
901
849
902
850
def __deepcopy__ (self : T , _ : Any = {}) -> T :
903
851
kwargs = {}
904
852
for name in self ._betterproto .sorted_field_names :
905
853
value = self .__raw_get (name )
906
- if value is not PLACEHOLDER :
907
- kwargs [name ] = deepcopy (value )
854
+ kwargs [name ] = deepcopy (value )
908
855
return self .__class__ (** kwargs ) # type: ignore
909
856
910
857
def __copy__ (self : T , _ : Any = {}) -> T :
911
858
kwargs = {}
912
859
for name in self ._betterproto .sorted_field_names :
913
860
value = self .__raw_get (name )
914
- if value is not PLACEHOLDER :
915
- kwargs [name ] = value
861
+ kwargs [name ] = value
916
862
return self .__class__ (** kwargs ) # type: ignore
917
863
918
864
@classproperty
@@ -1853,12 +1799,7 @@ def is_set(self, name: str) -> bool:
1853
1799
:class:`bool`
1854
1800
`True` if field has been set, otherwise `False`.
1855
1801
"""
1856
- default = (
1857
- PLACEHOLDER
1858
- if not self ._betterproto .meta_by_field_name [name ].optional
1859
- else None
1860
- )
1861
- return self .__raw_get (name ) is not default
1802
+ return self .__raw_get (name ) is not self ._get_field_default (name )
1862
1803
1863
1804
@classmethod
1864
1805
def _validate_field_groups (cls , values ):
0 commit comments