betterproto2-compiler 0.7.0__py3-none-any.whl → 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,16 +4,6 @@
4
4
  # This file has been @generated
5
5
 
6
6
  __all__ = (
7
- "FieldCardinality",
8
- "FieldKind",
9
- "FieldDescriptorProtoLabel",
10
- "FieldDescriptorProtoType",
11
- "FieldOptionsCType",
12
- "FieldOptionsJsType",
13
- "FileOptionsOptimizeMode",
14
- "MethodOptionsIdempotencyLevel",
15
- "NullValue",
16
- "Syntax",
17
7
  "Any",
18
8
  "Api",
19
9
  "BoolValue",
@@ -23,6 +13,7 @@ __all__ = (
23
13
  "DescriptorProtoReservedRange",
24
14
  "DoubleValue",
25
15
  "Duration",
16
+ "Edition",
26
17
  "Empty",
27
18
  "Enum",
28
19
  "EnumDescriptorProto",
@@ -32,16 +23,39 @@ __all__ = (
32
23
  "EnumValueDescriptorProto",
33
24
  "EnumValueOptions",
34
25
  "ExtensionRangeOptions",
26
+ "ExtensionRangeOptionsDeclaration",
27
+ "ExtensionRangeOptionsVerificationState",
28
+ "FeatureSet",
29
+ "FeatureSetDefaults",
30
+ "FeatureSetDefaultsFeatureSetEditionDefault",
31
+ "FeatureSetEnumType",
32
+ "FeatureSetFieldPresence",
33
+ "FeatureSetJsonFormat",
34
+ "FeatureSetMessageEncoding",
35
+ "FeatureSetRepeatedFieldEncoding",
36
+ "FeatureSetUtf8Validation",
35
37
  "Field",
38
+ "FieldCardinality",
36
39
  "FieldDescriptorProto",
40
+ "FieldDescriptorProtoLabel",
41
+ "FieldDescriptorProtoType",
42
+ "FieldKind",
37
43
  "FieldMask",
38
44
  "FieldOptions",
45
+ "FieldOptionsCType",
46
+ "FieldOptionsEditionDefault",
47
+ "FieldOptionsFeatureSupport",
48
+ "FieldOptionsJsType",
49
+ "FieldOptionsOptionRetention",
50
+ "FieldOptionsOptionTargetType",
39
51
  "FileDescriptorProto",
40
52
  "FileDescriptorSet",
41
53
  "FileOptions",
54
+ "FileOptionsOptimizeMode",
42
55
  "FloatValue",
43
56
  "GeneratedCodeInfo",
44
57
  "GeneratedCodeInfoAnnotation",
58
+ "GeneratedCodeInfoAnnotationSemantic",
45
59
  "Int32Value",
46
60
  "Int64Value",
47
61
  "ListValue",
@@ -49,7 +63,9 @@ __all__ = (
49
63
  "Method",
50
64
  "MethodDescriptorProto",
51
65
  "MethodOptions",
66
+ "MethodOptionsIdempotencyLevel",
52
67
  "Mixin",
68
+ "NullValue",
53
69
  "OneofDescriptorProto",
54
70
  "OneofOptions",
55
71
  "Option",
@@ -60,6 +76,7 @@ __all__ = (
60
76
  "SourceContext",
61
77
  "StringValue",
62
78
  "Struct",
79
+ "Syntax",
63
80
  "Timestamp",
64
81
  "Type",
65
82
  "UInt32Value",
@@ -80,7 +97,162 @@ import dateutil.parser
80
97
 
81
98
  from ...message_pool import default_message_pool
82
99
 
83
- betterproto2.check_compiler_version("0.7.0")
100
+ _COMPILER_VERSION = "0.8.0"
101
+ betterproto2.check_compiler_version(_COMPILER_VERSION)
102
+
103
+
104
+ class Edition(betterproto2.Enum):
105
+ """
106
+ The full set of known editions.
107
+ """
108
+
109
+ UNKNOWN = 0
110
+ """
111
+ A placeholder for an unknown edition value.
112
+ """
113
+
114
+ LEGACY = 900
115
+ """
116
+ A placeholder edition for specifying default behaviors *before* a feature
117
+ was first introduced. This is effectively an "infinite past".
118
+ """
119
+
120
+ PROTO2 = 998
121
+ """
122
+ Legacy syntax "editions". These pre-date editions, but behave much like
123
+ distinct editions. These can't be used to specify the edition of proto
124
+ files, but feature definitions must supply proto2/proto3 defaults for
125
+ backwards compatibility.
126
+ """
127
+
128
+ PROTO3 = 999
129
+
130
+ _2023 = 1000
131
+ """
132
+ Editions that have been released. The specific values are arbitrary and
133
+ should not be depended on, but they will always be time-ordered for easy
134
+ comparison.
135
+ """
136
+
137
+ _2024 = 1001
138
+
139
+ _1_TEST_ONLY = 1
140
+ """
141
+ Placeholder editions for testing feature resolution. These should not be
142
+ used or relied on outside of tests.
143
+ """
144
+
145
+ _2_TEST_ONLY = 2
146
+
147
+ _99997_TEST_ONLY = 99997
148
+
149
+ _99998_TEST_ONLY = 99998
150
+
151
+ _99999_TEST_ONLY = 99999
152
+
153
+ MAX = 2147483647
154
+ """
155
+ Placeholder for specifying unbounded edition support. This should only
156
+ ever be used by plugins that can expect to never require any changes to
157
+ support a new edition.
158
+ """
159
+
160
+ @classmethod
161
+ def betterproto_value_to_renamed_proto_names(cls) -> dict[int, str]:
162
+ return {
163
+ 0: "EDITION_UNKNOWN",
164
+ 900: "EDITION_LEGACY",
165
+ 998: "EDITION_PROTO2",
166
+ 999: "EDITION_PROTO3",
167
+ 1000: "EDITION_2023",
168
+ 1001: "EDITION_2024",
169
+ 1: "EDITION_1_TEST_ONLY",
170
+ 2: "EDITION_2_TEST_ONLY",
171
+ 99997: "EDITION_99997_TEST_ONLY",
172
+ 99998: "EDITION_99998_TEST_ONLY",
173
+ 99999: "EDITION_99999_TEST_ONLY",
174
+ 2147483647: "EDITION_MAX",
175
+ }
176
+
177
+ @classmethod
178
+ def betterproto_renamed_proto_names_to_value(cls) -> dict[str, int]:
179
+ return {
180
+ "EDITION_UNKNOWN": 0,
181
+ "EDITION_LEGACY": 900,
182
+ "EDITION_PROTO2": 998,
183
+ "EDITION_PROTO3": 999,
184
+ "EDITION_2023": 1000,
185
+ "EDITION_2024": 1001,
186
+ "EDITION_1_TEST_ONLY": 1,
187
+ "EDITION_2_TEST_ONLY": 2,
188
+ "EDITION_99997_TEST_ONLY": 99997,
189
+ "EDITION_99998_TEST_ONLY": 99998,
190
+ "EDITION_99999_TEST_ONLY": 99999,
191
+ "EDITION_MAX": 2147483647,
192
+ }
193
+
194
+
195
+ class ExtensionRangeOptionsVerificationState(betterproto2.Enum):
196
+ """
197
+ The verification state of the extension range.
198
+ """
199
+
200
+ DECLARATION = 0
201
+ """
202
+ All the extensions of the range must be declared.
203
+ """
204
+
205
+ UNVERIFIED = 1
206
+
207
+
208
+ class FeatureSetEnumType(betterproto2.Enum):
209
+ ENUM_TYPE_UNKNOWN = 0
210
+
211
+ OPEN = 1
212
+
213
+ CLOSED = 2
214
+
215
+
216
+ class FeatureSetFieldPresence(betterproto2.Enum):
217
+ FIELD_PRESENCE_UNKNOWN = 0
218
+
219
+ EXPLICIT = 1
220
+
221
+ IMPLICIT = 2
222
+
223
+ LEGACY_REQUIRED = 3
224
+
225
+
226
+ class FeatureSetJsonFormat(betterproto2.Enum):
227
+ JSON_FORMAT_UNKNOWN = 0
228
+
229
+ ALLOW = 1
230
+
231
+ LEGACY_BEST_EFFORT = 2
232
+
233
+
234
+ class FeatureSetMessageEncoding(betterproto2.Enum):
235
+ MESSAGE_ENCODING_UNKNOWN = 0
236
+
237
+ LENGTH_PREFIXED = 1
238
+
239
+ DELIMITED = 2
240
+
241
+
242
+ class FeatureSetRepeatedFieldEncoding(betterproto2.Enum):
243
+ REPEATED_FIELD_ENCODING_UNKNOWN = 0
244
+
245
+ PACKED = 1
246
+
247
+ EXPANDED = 2
248
+
249
+
250
+ class FeatureSetUtf8Validation(betterproto2.Enum):
251
+ UTF8_VALIDATION_UNKNOWN = 0
252
+
253
+ VERIFY = 2
254
+
255
+ NONE = 3
84
256
 
85
257
 
86
258
  class FieldCardinality(betterproto2.Enum):
@@ -88,26 +260,44 @@ class FieldCardinality(betterproto2.Enum):
88
260
  Whether a field is optional, required, or repeated.
89
261
  """
90
262
 
91
- CARDINALITY_UNKNOWN = 0
263
+ UNKNOWN = 0
92
264
  """
93
265
  For fields with unknown cardinality.
94
266
  """
95
267
 
96
- CARDINALITY_OPTIONAL = 1
268
+ OPTIONAL = 1
97
269
  """
98
270
  For optional fields.
99
271
  """
100
272
 
101
- CARDINALITY_REQUIRED = 2
273
+ REQUIRED = 2
102
274
  """
103
275
  For required fields. Proto2 syntax only.
104
276
  """
105
277
 
106
- CARDINALITY_REPEATED = 3
278
+ REPEATED = 3
107
279
  """
108
280
  For repeated fields.
109
281
  """
110
282
 
283
+ @classmethod
284
+ def betterproto_value_to_renamed_proto_names(cls) -> dict[int, str]:
285
+ return {
286
+ 0: "CARDINALITY_UNKNOWN",
287
+ 1: "CARDINALITY_OPTIONAL",
288
+ 2: "CARDINALITY_REQUIRED",
289
+ 3: "CARDINALITY_REPEATED",
290
+ }
291
+
292
+ @classmethod
293
+ def betterproto_renamed_proto_names_to_value(cls) -> dict[str, int]:
294
+ return {
295
+ "CARDINALITY_UNKNOWN": 0,
296
+ "CARDINALITY_OPTIONAL": 1,
297
+ "CARDINALITY_REQUIRED": 2,
298
+ "CARDINALITY_REPEATED": 3,
299
+ }
300
+
111
301
 
112
302
  class FieldKind(betterproto2.Enum):
113
303
  """
@@ -211,83 +401,151 @@ class FieldKind(betterproto2.Enum):
211
401
 
212
402
 
213
403
  class FieldDescriptorProtoLabel(betterproto2.Enum):
214
- LABEL_OPTIONAL = 1
404
+ OPTIONAL = 1
215
405
  """
216
406
  0 is reserved for errors
217
407
  """
218
408
 
219
- LABEL_REQUIRED = 2
409
+ REPEATED = 3
410
+
411
+ REQUIRED = 2
412
+ """
413
+ The required label is only allowed in google.protobuf. In proto3 and Editions
414
+ it's explicitly prohibited. In Editions, the `field_presence` feature
415
+ can be used to get this behavior.
416
+ """
417
+
418
+ @classmethod
419
+ def betterproto_value_to_renamed_proto_names(cls) -> dict[int, str]:
420
+ return {
421
+ 1: "LABEL_OPTIONAL",
422
+ 3: "LABEL_REPEATED",
423
+ 2: "LABEL_REQUIRED",
424
+ }
220
425
 
221
- LABEL_REPEATED = 3
426
+ @classmethod
427
+ def betterproto_renamed_proto_names_to_value(cls) -> dict[str, int]:
428
+ return {
429
+ "LABEL_OPTIONAL": 1,
430
+ "LABEL_REPEATED": 3,
431
+ "LABEL_REQUIRED": 2,
432
+ }
222
433
 
223
434
 
224
435
  class FieldDescriptorProtoType(betterproto2.Enum):
225
- TYPE_DOUBLE = 1
436
+ DOUBLE = 1
226
437
  """
227
438
  0 is reserved for errors.
228
439
  Order is weird for historical reasons.
229
440
  """
230
441
 
231
- TYPE_FLOAT = 2
442
+ FLOAT = 2
232
443
 
233
- TYPE_INT64 = 3
444
+ INT64 = 3
234
445
  """
235
446
  Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
236
447
  negative values are likely.
237
448
  """
238
449
 
239
- TYPE_UINT64 = 4
450
+ UINT64 = 4
240
451
 
241
- TYPE_INT32 = 5
452
+ INT32 = 5
242
453
  """
243
454
  Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
244
455
  negative values are likely.
245
456
  """
246
457
 
247
- TYPE_FIXED64 = 6
458
+ FIXED64 = 6
248
459
 
249
- TYPE_FIXED32 = 7
460
+ FIXED32 = 7
250
461
 
251
- TYPE_BOOL = 8
462
+ BOOL = 8
252
463
 
253
- TYPE_STRING = 9
464
+ STRING = 9
254
465
 
255
- TYPE_GROUP = 10
466
+ GROUP = 10
256
467
  """
257
468
  Tag-delimited aggregate.
258
- Group type is deprecated and not supported in proto3. However, Proto3
469
+ Group type is deprecated and not supported after google.protobuf. However, Proto3
259
470
  implementations should still be able to parse the group wire format and
260
- treat group fields as unknown fields.
471
+ treat group fields as unknown fields. In Editions, the group wire format
472
+ can be enabled via the `message_encoding` feature.
261
473
  """
262
474
 
263
- TYPE_MESSAGE = 11
475
+ MESSAGE = 11
264
476
  """
265
477
  Length-delimited aggregate.
266
478
  """
267
479
 
268
- TYPE_BYTES = 12
480
+ BYTES = 12
269
481
  """
270
482
  New in version 2.
271
483
  """
272
484
 
273
- TYPE_UINT32 = 13
485
+ UINT32 = 13
274
486
 
275
- TYPE_ENUM = 14
487
+ ENUM = 14
276
488
 
277
- TYPE_SFIXED32 = 15
489
+ SFIXED32 = 15
278
490
 
279
- TYPE_SFIXED64 = 16
491
+ SFIXED64 = 16
280
492
 
281
- TYPE_SINT32 = 17
493
+ SINT32 = 17
282
494
  """
283
495
  Uses ZigZag encoding.
284
496
  """
285
497
 
286
- TYPE_SINT64 = 18
498
+ SINT64 = 18
287
499
  """
288
500
  Uses ZigZag encoding.
289
501
  """
290
502
 
503
+ @classmethod
504
+ def betterproto_value_to_renamed_proto_names(cls) -> dict[int, str]:
505
+ return {
506
+ 1: "TYPE_DOUBLE",
507
+ 2: "TYPE_FLOAT",
508
+ 3: "TYPE_INT64",
509
+ 4: "TYPE_UINT64",
510
+ 5: "TYPE_INT32",
511
+ 6: "TYPE_FIXED64",
512
+ 7: "TYPE_FIXED32",
513
+ 8: "TYPE_BOOL",
514
+ 9: "TYPE_STRING",
515
+ 10: "TYPE_GROUP",
516
+ 11: "TYPE_MESSAGE",
517
+ 12: "TYPE_BYTES",
518
+ 13: "TYPE_UINT32",
519
+ 14: "TYPE_ENUM",
520
+ 15: "TYPE_SFIXED32",
521
+ 16: "TYPE_SFIXED64",
522
+ 17: "TYPE_SINT32",
523
+ 18: "TYPE_SINT64",
524
+ }
525
+
526
+ @classmethod
527
+ def betterproto_renamed_proto_names_to_value(cls) -> dict[str, int]:
528
+ return {
529
+ "TYPE_DOUBLE": 1,
530
+ "TYPE_FLOAT": 2,
531
+ "TYPE_INT64": 3,
532
+ "TYPE_UINT64": 4,
533
+ "TYPE_INT32": 5,
534
+ "TYPE_FIXED64": 6,
535
+ "TYPE_FIXED32": 7,
536
+ "TYPE_BOOL": 8,
537
+ "TYPE_STRING": 9,
538
+ "TYPE_GROUP": 10,
539
+ "TYPE_MESSAGE": 11,
540
+ "TYPE_BYTES": 12,
541
+ "TYPE_UINT32": 13,
542
+ "TYPE_ENUM": 14,
543
+ "TYPE_SFIXED32": 15,
544
+ "TYPE_SFIXED64": 16,
545
+ "TYPE_SINT32": 17,
546
+ "TYPE_SINT64": 18,
547
+ }
548
+
291
549
 
292
550
  class FieldOptionsCType(betterproto2.Enum):
293
551
  STRING = 0
@@ -296,6 +554,14 @@ class FieldOptionsCType(betterproto2.Enum):
296
554
  """
297
555
 
298
556
  CORD = 1
557
+ """
558
+ The option [ctype=CORD] may be applied to a non-repeated field of type
559
+ "bytes". It indicates that in C++, the data should be stored in a Cord
560
+ instead of a string. For very large strings, this may reduce memory
561
+ fragmentation. It may also allow better performance when parsing from a
562
+ Cord, or when parsing with aliasing enabled, as the parsed Cord may then
563
+ alias the original buffer.
564
+ """
299
565
 
300
566
  STRING_PIECE = 2
301
567
 
@@ -317,6 +583,46 @@ class FieldOptionsJsType(betterproto2.Enum):
317
583
  """
318
584
 
319
585
 
586
+ class FieldOptionsOptionRetention(betterproto2.Enum):
587
+ """
588
+ If set to RETENTION_SOURCE, the option will be omitted from the binary.
589
+ """
590
+
591
+ RETENTION_UNKNOWN = 0
592
+
593
+ RETENTION_RUNTIME = 1
594
+
595
+ RETENTION_SOURCE = 2
596
+
597
+
598
+ class FieldOptionsOptionTargetType(betterproto2.Enum):
599
+ """
600
+ This indicates the types of entities that the field may apply to when used
601
+ as an option. If it is unset, then the field may be freely used as an
602
+ option on any kind of entity.
603
+ """
604
+
605
+ TARGET_TYPE_UNKNOWN = 0
606
+
607
+ TARGET_TYPE_FILE = 1
608
+
609
+ TARGET_TYPE_EXTENSION_RANGE = 2
610
+
611
+ TARGET_TYPE_MESSAGE = 3
612
+
613
+ TARGET_TYPE_FIELD = 4
614
+
615
+ TARGET_TYPE_ONEOF = 5
616
+
617
+ TARGET_TYPE_ENUM = 6
618
+
619
+ TARGET_TYPE_ENUM_ENTRY = 7
620
+
621
+ TARGET_TYPE_SERVICE = 8
622
+
623
+ TARGET_TYPE_METHOD = 9
624
+
625
+
320
626
  class FileOptionsOptimizeMode(betterproto2.Enum):
321
627
  """
322
628
  Generated classes can be optimized for speed or code size.
@@ -340,6 +646,28 @@ class FileOptionsOptimizeMode(betterproto2.Enum):
340
646
  """
341
647
 
342
648
 
649
+ class GeneratedCodeInfoAnnotationSemantic(betterproto2.Enum):
650
+ """
651
+ Represents the identified object's effect on the element in the original
652
+ .proto file.
653
+ """
654
+
655
+ NONE = 0
656
+ """
657
+ There is no effect or the effect is indescribable.
658
+ """
659
+
660
+ SET = 1
661
+ """
662
+ The element is set or otherwise mutated.
663
+ """
664
+
665
+ ALIAS = 2
666
+ """
667
+ An alias to the element is returned.
668
+ """
669
+
670
+
343
671
  class MethodOptionsIdempotencyLevel(betterproto2.Enum):
344
672
  """
345
673
  Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
@@ -365,10 +693,10 @@ class NullValue(betterproto2.Enum):
365
693
  `NullValue` is a singleton enumeration to represent the null value for the
366
694
  `Value` type union.
367
695
 
368
- The JSON representation for `NullValue` is JSON `null`.
696
+ The JSON representation for `NullValue` is JSON `null`.
369
697
  """
370
698
 
371
- _ = 0
699
+ NULL_VALUE = 0
372
700
  """
373
701
  Null value.
374
702
  """
@@ -389,6 +717,27 @@ class Syntax(betterproto2.Enum):
389
717
  Syntax `proto3`.
390
718
  """
391
719
 
720
+ EDITIONS = 2
721
+ """
722
+ Syntax `editions`.
723
+ """
724
+
725
+ @classmethod
726
+ def betterproto_value_to_renamed_proto_names(cls) -> dict[int, str]:
727
+ return {
728
+ 0: "SYNTAX_PROTO2",
729
+ 1: "SYNTAX_PROTO3",
730
+ 2: "SYNTAX_EDITIONS",
731
+ }
732
+
733
+ @classmethod
734
+ def betterproto_renamed_proto_names_to_value(cls) -> dict[str, int]:
735
+ return {
736
+ "SYNTAX_PROTO2": 0,
737
+ "SYNTAX_PROTO3": 1,
738
+ "SYNTAX_EDITIONS": 2,
739
+ }
740
+
392
741
 
393
742
  @dataclass(eq=False, repr=False)
394
743
  class Any(betterproto2.Message):
@@ -417,8 +766,12 @@ class Any(betterproto2.Message):
417
766
  if (any.is(Foo.class)) {
418
767
  foo = any.unpack(Foo.class);
419
768
  }
769
+ // or ...
770
+ if (any.isSameTypeAs(Foo.getDefaultInstance())) {
771
+ foo = any.unpack(Foo.getDefaultInstance());
772
+ }
420
773
 
421
- Example 3: Pack and unpack a message in Python.
774
+ Example 3: Pack and unpack a message in Python.
422
775
 
423
776
  foo = Foo(...)
424
777
  any = Any()
@@ -428,7 +781,7 @@ class Any(betterproto2.Message):
428
781
  any.Unpack(foo)
429
782
  ...
430
783
 
431
- Example 4: Pack and unpack a message in Go
784
+ Example 4: Pack and unpack a message in Go
432
785
 
433
786
  foo := &pb.Foo{...}
434
787
  any, err := anypb.New(foo)
@@ -448,7 +801,7 @@ class Any(betterproto2.Message):
448
801
  name "y.z".
449
802
 
450
803
  JSON
451
-
804
+ ====
452
805
  The JSON representation of an `Any` value uses the regular
453
806
  representation of the deserialized, embedded message, with an
454
807
  additional field `@type` which contains the type URL. Example:
@@ -501,7 +854,8 @@ class Any(betterproto2.Message):
501
854
 
502
855
  Note: this functionality is not currently available in the official
503
856
  protobuf release, and it is not used for type URLs beginning with
504
- type.googleapis.com.
857
+ type.googleapis.com. As of May 2023, there are no widely used type server
858
+ implementations and no plans to implement one.
505
859
 
506
860
  Schemes other than `http`, `https` (or the empty scheme) might be
507
861
  used with implementation specific semantics.
@@ -512,7 +866,8 @@ class Any(betterproto2.Message):
512
866
  Must be a valid serialized protocol buffer of the above specified type.
513
867
  """
514
868
 
515
- def pack(self, message: betterproto2.Message, message_pool: "betterproto2.MessagePool | None" = None) -> None:
869
+ @classmethod
870
+ def pack(cls, message: betterproto2.Message, message_pool: "betterproto2.MessagePool | None" = None) -> "Any":
516
871
  """
517
872
  Pack the given message in the `Any` object.
518
873
 
@@ -521,8 +876,10 @@ class Any(betterproto2.Message):
521
876
  """
522
877
  message_pool = message_pool or default_message_pool
523
878
 
524
- self.type_url = message_pool.type_to_url[type(message)]
525
- self.value = bytes(message)
879
+ type_url = message_pool.type_to_url[type(message)]
880
+ value = bytes(message)
881
+
882
+ return cls(type_url=type_url, value=value)
526
883
 
527
884
  def unpack(self, message_pool: "betterproto2.MessagePool | None" = None) -> betterproto2.Message | None:
528
885
  """
@@ -541,7 +898,7 @@ class Any(betterproto2.Message):
541
898
  except KeyError:
542
899
  raise TypeError(f"Can't unpack unregistered type: {self.type_url}")
543
900
 
544
- return message_type().parse(self.value)
901
+ return message_type.parse(self.value)
545
902
 
546
903
  def to_dict(self, **kwargs) -> dict[str, typing.Any]:
547
904
  # TODO allow passing a message pool to `to_dict`
@@ -559,6 +916,23 @@ class Any(betterproto2.Message):
559
916
 
560
917
  return output
561
918
 
919
+ @classmethod
920
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
921
+ value = dict(value) # Make a copy
922
+
923
+ type_url = value.pop("@type", None)
924
+ msg_cls = default_message_pool.url_to_type.get(type_url, None)
925
+
926
+ if not msg_cls:
927
+ raise TypeError(f"Can't unpack unregistered type: {type_url}")
928
+
929
+ if not msg_cls.to_dict == betterproto2.Message.to_dict:
930
+ value = value["value"]
931
+
932
+ return cls(
933
+ type_url=type_url, value=bytes(msg_cls.from_dict(value, ignore_unknown_fields=ignore_unknown_fields))
934
+ )
935
+
562
936
 
563
937
  default_message_pool.register_message("google.protobuf", "Any", Any)
564
938
 
@@ -650,10 +1024,10 @@ class BoolValue(betterproto2.Message):
650
1024
  """
651
1025
 
652
1026
  @classmethod
653
- def from_dict(cls, value):
1027
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
654
1028
  if isinstance(value, bool):
655
1029
  return BoolValue(value=value)
656
- return super().from_dict(value)
1030
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
657
1031
 
658
1032
  def to_dict(
659
1033
  self,
@@ -689,10 +1063,10 @@ class BytesValue(betterproto2.Message):
689
1063
  """
690
1064
 
691
1065
  @classmethod
692
- def from_dict(cls, value):
1066
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
693
1067
  if isinstance(value, bytes):
694
1068
  return BytesValue(value=value)
695
- return super().from_dict(value)
1069
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
696
1070
 
697
1071
  def to_dict(
698
1072
  self,
@@ -808,10 +1182,10 @@ class DoubleValue(betterproto2.Message):
808
1182
  """
809
1183
 
810
1184
  @classmethod
811
- def from_dict(cls, value):
1185
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
812
1186
  if isinstance(value, float):
813
1187
  return DoubleValue(value=value)
814
- return super().from_dict(value)
1188
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
815
1189
 
816
1190
  def to_dict(
817
1191
  self,
@@ -934,7 +1308,7 @@ class Duration(betterproto2.Message):
934
1308
  return f"{'.'.join(parts)}s"
935
1309
 
936
1310
  @classmethod
937
- def from_dict(cls, value):
1311
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
938
1312
  if isinstance(value, str):
939
1313
  if not re.match(r"^\d+(\.\d+)?s$", value):
940
1314
  raise ValueError(f"Invalid duration string: {value}")
@@ -942,7 +1316,7 @@ class Duration(betterproto2.Message):
942
1316
  seconds = float(value[:-1])
943
1317
  return Duration(seconds=int(seconds), nanos=int((seconds - int(seconds)) * 1e9))
944
1318
 
945
- return super().from_dict(value)
1319
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
946
1320
 
947
1321
  def to_dict(
948
1322
  self,
@@ -1025,6 +1399,11 @@ class Enum(betterproto2.Message):
1025
1399
  The source syntax.
1026
1400
  """
1027
1401
 
1402
+ edition: "str" = betterproto2.field(6, betterproto2.TYPE_STRING)
1403
+ """
1404
+ The source edition string, only valid when syntax is SYNTAX_EDITIONS.
1405
+ """
1406
+
1028
1407
 
1029
1408
  default_message_pool.register_message("google.protobuf", "Enum", Enum)
1030
1409
 
@@ -1103,6 +1482,21 @@ class EnumOptions(betterproto2.Message):
1103
1482
  is a formalization for deprecating enums.
1104
1483
  """
1105
1484
 
1485
+ deprecated_legacy_json_field_conflicts: "bool" = betterproto2.field(6, betterproto2.TYPE_BOOL)
1486
+ """
1487
+ Enable the legacy handling of JSON field name conflicts. This lowercases
1488
+ and strips underscored from the fields before comparison in proto3 only.
1489
+ The new behavior takes `json_name` into account and applies to proto2 as
1490
+ well.
1491
+ TODO Remove this legacy behavior once downstream teams have
1492
+ had time to migrate.
1493
+ """
1494
+
1495
+ features: "FeatureSet | None" = betterproto2.field(7, betterproto2.TYPE_MESSAGE, optional=True)
1496
+ """
1497
+ Any features defined in the specific edition.
1498
+ """
1499
+
1106
1500
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
1107
1501
  999, betterproto2.TYPE_MESSAGE, repeated=True
1108
1502
  )
@@ -1110,6 +1504,11 @@ class EnumOptions(betterproto2.Message):
1110
1504
  The parser stores options it doesn't recognize here. See above.
1111
1505
  """
1112
1506
 
1507
+ def __post_init__(self) -> None:
1508
+ super().__post_init__()
1509
+ if self.is_set("deprecated_legacy_json_field_conflicts"):
1510
+ warnings.warn("EnumOptions.deprecated_legacy_json_field_conflicts is deprecated", DeprecationWarning)
1511
+
1113
1512
 
1114
1513
  default_message_pool.register_message("google.protobuf", "EnumOptions", EnumOptions)
1115
1514
 
@@ -1165,6 +1564,25 @@ class EnumValueOptions(betterproto2.Message):
1165
1564
  this is a formalization for deprecating enum values.
1166
1565
  """
1167
1566
 
1567
+ features: "FeatureSet | None" = betterproto2.field(2, betterproto2.TYPE_MESSAGE, optional=True)
1568
+ """
1569
+ Any features defined in the specific edition.
1570
+ """
1571
+
1572
+ debug_redact: "bool" = betterproto2.field(3, betterproto2.TYPE_BOOL)
1573
+ """
1574
+ Indicate that fields annotated with this enum value should not be printed
1575
+ out when using debug formats, e.g. when the field contains sensitive
1576
+ credentials.
1577
+ """
1578
+
1579
+ feature_support: "FieldOptionsFeatureSupport | None" = betterproto2.field(
1580
+ 4, betterproto2.TYPE_MESSAGE, optional=True
1581
+ )
1582
+ """
1583
+ Information about the support window of a feature value.
1584
+ """
1585
+
1168
1586
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
1169
1587
  999, betterproto2.TYPE_MESSAGE, repeated=True
1170
1588
  )
@@ -1185,10 +1603,170 @@ class ExtensionRangeOptions(betterproto2.Message):
1185
1603
  The parser stores options it doesn't recognize here. See above.
1186
1604
  """
1187
1605
 
1606
+ declaration: "list[ExtensionRangeOptionsDeclaration]" = betterproto2.field(
1607
+ 2, betterproto2.TYPE_MESSAGE, repeated=True
1608
+ )
1609
+ """
1610
+ For external users: DO NOT USE. We are in the process of open sourcing
1611
+ extension declaration and executing internal cleanups before it can be
1612
+ used externally.
1613
+ """
1614
+
1615
+ features: "FeatureSet | None" = betterproto2.field(50, betterproto2.TYPE_MESSAGE, optional=True)
1616
+ """
1617
+ Any features defined in the specific edition.
1618
+ """
1619
+
1620
+ verification: "ExtensionRangeOptionsVerificationState" = betterproto2.field(
1621
+ 3, betterproto2.TYPE_ENUM, default_factory=lambda: ExtensionRangeOptionsVerificationState(0)
1622
+ )
1623
+ """
1624
+ The verification state of the range.
1625
+ TODO: flip the default to DECLARATION once all empty ranges
1626
+ are marked as UNVERIFIED.
1627
+ """
1628
+
1188
1629
 
1189
1630
  default_message_pool.register_message("google.protobuf", "ExtensionRangeOptions", ExtensionRangeOptions)
1190
1631
 
1191
1632
 
1633
+ @dataclass(eq=False, repr=False)
1634
+ class ExtensionRangeOptionsDeclaration(betterproto2.Message):
1635
+ number: "int" = betterproto2.field(1, betterproto2.TYPE_INT32)
1636
+ """
1637
+ The extension number declared within the extension range.
1638
+ """
1639
+
1640
+ full_name: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
1641
+ """
1642
+ The fully-qualified name of the extension field. There must be a leading
1643
+ dot in front of the full name.
1644
+ """
1645
+
1646
+ type: "str" = betterproto2.field(3, betterproto2.TYPE_STRING)
1647
+ """
1648
+ The fully-qualified type name of the extension field. Unlike
1649
+ Metadata.type, Declaration.type must have a leading dot for messages
1650
+ and enums.
1651
+ """
1652
+
1653
+ reserved: "bool" = betterproto2.field(5, betterproto2.TYPE_BOOL)
1654
+ """
1655
+ If true, indicates that the number is reserved in the extension range,
1656
+ and any extension field with the number will fail to compile. Set this
1657
+ when a declared extension field is deleted.
1658
+ """
1659
+
1660
+ repeated: "bool" = betterproto2.field(6, betterproto2.TYPE_BOOL)
1661
+ """
1662
+ If true, indicates that the extension must be defined as repeated.
1663
+ Otherwise the extension must be defined as optional.
1664
+ """
1665
+
1666
+
1667
+ default_message_pool.register_message(
1668
+ "google.protobuf", "ExtensionRangeOptions.Declaration", ExtensionRangeOptionsDeclaration
1669
+ )
1670
+
1671
+
1672
+ @dataclass(eq=False, repr=False)
1673
+ class FeatureSet(betterproto2.Message):
1674
+ """
1675
+ ===================================================================
1676
+ Features
1677
+
1678
+ TODO Enums in C++ gencode (and potentially other languages) are
1679
+ not well scoped. This means that each of the feature enums below can clash
1680
+ with each other. The short names we've chosen maximize call-site
1681
+ readability, but leave us very open to this scenario. A future feature will
1682
+ be designed and implemented to handle this, hopefully before we ever hit a
1683
+ conflict here.
1684
+ """
1685
+
1686
+ field_presence: "FeatureSetFieldPresence" = betterproto2.field(
1687
+ 1, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetFieldPresence(0)
1688
+ )
1689
+
1690
+ enum_type: "FeatureSetEnumType" = betterproto2.field(
1691
+ 2, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetEnumType(0)
1692
+ )
1693
+
1694
+ repeated_field_encoding: "FeatureSetRepeatedFieldEncoding" = betterproto2.field(
1695
+ 3, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetRepeatedFieldEncoding(0)
1696
+ )
1697
+
1698
+ utf8_validation: "FeatureSetUtf8Validation" = betterproto2.field(
1699
+ 4, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetUtf8Validation(0)
1700
+ )
1701
+
1702
+ message_encoding: "FeatureSetMessageEncoding" = betterproto2.field(
1703
+ 5, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetMessageEncoding(0)
1704
+ )
1705
+
1706
+ json_format: "FeatureSetJsonFormat" = betterproto2.field(
1707
+ 6, betterproto2.TYPE_ENUM, default_factory=lambda: FeatureSetJsonFormat(0)
1708
+ )
1709
+
1710
+
1711
+ default_message_pool.register_message("google.protobuf", "FeatureSet", FeatureSet)
1712
+
1713
+
1714
+ @dataclass(eq=False, repr=False)
1715
+ class FeatureSetDefaults(betterproto2.Message):
1716
+ """
1717
+ A compiled specification for the defaults of a set of features. These
1718
+ messages are generated from FeatureSet extensions and can be used to seed
1719
+ feature resolution. The resolution with this object becomes a simple search
1720
+ for the closest matching edition, followed by proto merges.
1721
+ """
1722
+
1723
+ defaults: "list[FeatureSetDefaultsFeatureSetEditionDefault]" = betterproto2.field(
1724
+ 1, betterproto2.TYPE_MESSAGE, repeated=True
1725
+ )
1726
+
1727
+ minimum_edition: "Edition" = betterproto2.field(4, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
1728
+ """
1729
+ The minimum supported edition (inclusive) when this was constructed.
1730
+ Editions before this will not have defaults.
1731
+ """
1732
+
1733
+ maximum_edition: "Edition" = betterproto2.field(5, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
1734
+ """
1735
+ The maximum known edition (inclusive) when this was constructed. Editions
1736
+ after this will not have reliable defaults.
1737
+ """
1738
+
1739
+
1740
+ default_message_pool.register_message("google.protobuf", "FeatureSetDefaults", FeatureSetDefaults)
1741
+
1742
+
1743
+ @dataclass(eq=False, repr=False)
1744
+ class FeatureSetDefaultsFeatureSetEditionDefault(betterproto2.Message):
1745
+ """
1746
+ A map from every known edition with a unique set of defaults to its
1747
+ defaults. Not all editions may be contained here. For a given edition,
1748
+ the defaults at the closest matching edition ordered at or before it should
1749
+ be used. This field must be in strict ascending order by edition.
1750
+ """
1751
+
1752
+ edition: "Edition" = betterproto2.field(3, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
1753
+
1754
+ overridable_features: "FeatureSet | None" = betterproto2.field(4, betterproto2.TYPE_MESSAGE, optional=True)
1755
+ """
1756
+ Defaults of features that can be overridden in this edition.
1757
+ """
1758
+
1759
+ fixed_features: "FeatureSet | None" = betterproto2.field(5, betterproto2.TYPE_MESSAGE, optional=True)
1760
+ """
1761
+ Defaults of features that can't be overridden in this edition.
1762
+ """
1763
+
1764
+
1765
+ default_message_pool.register_message(
1766
+ "google.protobuf", "FeatureSetDefaults.FeatureSetEditionDefault", FeatureSetDefaultsFeatureSetEditionDefault
1767
+ )
1768
+
1769
+
1192
1770
  @dataclass(eq=False, repr=False)
1193
1771
  class Field(betterproto2.Message):
1194
1772
  """
@@ -1319,12 +1897,12 @@ class FieldDescriptorProto(betterproto2.Message):
1319
1897
  If true, this is a proto3 "optional". When a proto3 field is optional, it
1320
1898
  tracks presence regardless of field type.
1321
1899
 
1322
- When proto3_optional is true, this field must be belong to a oneof to
1323
- signal to old proto3 clients that presence is tracked for this field. This
1324
- oneof is known as a "synthetic" oneof, and this field must be its sole
1325
- member (each proto3 optional field gets its own synthetic oneof). Synthetic
1326
- oneofs exist in the descriptor only, and do not generate any API. Synthetic
1327
- oneofs must be ordered after all "real" oneofs.
1900
+ When proto3_optional is true, this field must belong to a oneof to signal
1901
+ to old proto3 clients that presence is tracked for this field. This oneof
1902
+ is known as a "synthetic" oneof, and this field must be its sole member
1903
+ (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs
1904
+ exist in the descriptor only, and do not generate any API. Synthetic oneofs
1905
+ must be ordered after all "real" oneofs.
1328
1906
 
1329
1907
  For message fields, proto3_optional doesn't create any semantic change,
1330
1908
  since non-repeated message fields always track presence. However it still
@@ -1561,10 +2139,13 @@ class FieldOptions(betterproto2.Message):
1561
2139
  1, betterproto2.TYPE_ENUM, default_factory=lambda: FieldOptionsCType(0)
1562
2140
  )
1563
2141
  """
2142
+ NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead.
1564
2143
  The ctype option instructs the C++ code generator to use a different
1565
2144
  representation of the field than it normally would. See the specific
1566
- options below. This option is not yet implemented in the open source
1567
- release -- sorry, we'll try to include it in a future version!
2145
+ options below. This option is only implemented to support use of
2146
+ [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of
2147
+ type "bytes" in the open source release.
2148
+ TODO: make ctype actually deprecated.
1568
2149
  """
1569
2150
 
1570
2151
  packed: "bool" = betterproto2.field(2, betterproto2.TYPE_BOOL)
@@ -1573,7 +2154,9 @@ class FieldOptions(betterproto2.Message):
1573
2154
  a more efficient representation on the wire. Rather than repeatedly
1574
2155
  writing the tag and type for each element, the entire array is encoded as
1575
2156
  a single length-delimited blob. In proto3, only explicit setting it to
1576
- false will avoid using packed encoding.
2157
+ false will avoid using packed encoding. This option is prohibited in
2158
+ Editions, but the `repeated_field_encoding` feature can be used to control
2159
+ the behavior.
1577
2160
  """
1578
2161
 
1579
2162
  jstype: "FieldOptionsJsType" = betterproto2.field(
@@ -1612,22 +2195,11 @@ class FieldOptions(betterproto2.Message):
1612
2195
  call from multiple threads concurrently, while non-const methods continue
1613
2196
  to require exclusive access.
1614
2197
 
1615
- Note that implementations may choose not to check required fields within
1616
- a lazy sub-message. That is, calling IsInitialized() on the outer message
1617
- may return true even if the inner message has missing required fields.
1618
- This is necessary because otherwise the inner message would have to be
1619
- parsed in order to perform the check, defeating the purpose of lazy
1620
- parsing. An implementation which chooses not to check required fields
1621
- must be consistent about it. That is, for any particular sub-message, the
1622
- implementation must either *always* check its required fields, or *never*
1623
- check its required fields, regardless of whether or not the message has
1624
- been parsed.
1625
-
1626
- As of 2021, lazy does no correctness checks on the byte stream during
1627
- parsing. This may lead to crashes if and when an invalid byte stream is
1628
- finally parsed upon access.
1629
-
1630
- TODO(b/211906113): Enable validation on lazy fields.
2198
+ Note that lazy message fields are still eagerly verified to check
2199
+ ill-formed wireformat or missing required fields. Calling IsInitialized()
2200
+ on the outer message would fail if the inner message has missing required
2201
+ fields. Failed verification would result in parsing failure (except when
2202
+ uninitialized messages are acceptable).
1631
2203
  """
1632
2204
 
1633
2205
  unverified_lazy: "bool" = betterproto2.field(15, betterproto2.TYPE_BOOL)
@@ -1650,6 +2222,31 @@ class FieldOptions(betterproto2.Message):
1650
2222
  For Google-internal migration only. Do not use.
1651
2223
  """
1652
2224
 
2225
+ debug_redact: "bool" = betterproto2.field(16, betterproto2.TYPE_BOOL)
2226
+ """
2227
+ Indicate that the field value should not be printed out when using debug
2228
+ formats, e.g. when the field contains sensitive credentials.
2229
+ """
2230
+
2231
+ retention: "FieldOptionsOptionRetention" = betterproto2.field(
2232
+ 17, betterproto2.TYPE_ENUM, default_factory=lambda: FieldOptionsOptionRetention(0)
2233
+ )
2234
+
2235
+ targets: "list[FieldOptionsOptionTargetType]" = betterproto2.field(19, betterproto2.TYPE_ENUM, repeated=True)
2236
+
2237
+ edition_defaults: "list[FieldOptionsEditionDefault]" = betterproto2.field(
2238
+ 20, betterproto2.TYPE_MESSAGE, repeated=True
2239
+ )
2240
+
2241
+ features: "FeatureSet | None" = betterproto2.field(21, betterproto2.TYPE_MESSAGE, optional=True)
2242
+ """
2243
+ Any features defined in the specific edition.
2244
+ """
2245
+
2246
+ feature_support: "FieldOptionsFeatureSupport | None" = betterproto2.field(
2247
+ 22, betterproto2.TYPE_MESSAGE, optional=True
2248
+ )
2249
+
1653
2250
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
1654
2251
  999, betterproto2.TYPE_MESSAGE, repeated=True
1655
2252
  )
@@ -1661,6 +2258,55 @@ class FieldOptions(betterproto2.Message):
1661
2258
  default_message_pool.register_message("google.protobuf", "FieldOptions", FieldOptions)
1662
2259
 
1663
2260
 
2261
+ @dataclass(eq=False, repr=False)
2262
+ class FieldOptionsEditionDefault(betterproto2.Message):
2263
+ edition: "Edition" = betterproto2.field(3, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
2264
+
2265
+ value: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
2266
+ """
2267
+ Textproto value.
2268
+ """
2269
+
2270
+
2271
+ default_message_pool.register_message("google.protobuf", "FieldOptions.EditionDefault", FieldOptionsEditionDefault)
2272
+
2273
+
2274
+ @dataclass(eq=False, repr=False)
2275
+ class FieldOptionsFeatureSupport(betterproto2.Message):
2276
+ """
2277
+ Information about the support window of a feature.
2278
+ """
2279
+
2280
+ edition_introduced: "Edition" = betterproto2.field(1, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
2281
+ """
2282
+ The edition that this feature was first available in. In editions
2283
+ earlier than this one, the default assigned to EDITION_LEGACY will be
2284
+ used, and proto files will not be able to override it.
2285
+ """
2286
+
2287
+ edition_deprecated: "Edition" = betterproto2.field(2, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
2288
+ """
2289
+ The edition this feature becomes deprecated in. Using this after this
2290
+ edition may trigger warnings.
2291
+ """
2292
+
2293
+ deprecation_warning: "str" = betterproto2.field(3, betterproto2.TYPE_STRING)
2294
+ """
2295
+ The deprecation warning text if this feature is used after the edition it
2296
+ was marked deprecated in.
2297
+ """
2298
+
2299
+ edition_removed: "Edition" = betterproto2.field(4, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
2300
+ """
2301
+ The edition this feature is no longer available in. In editions after
2302
+ this one, the last default assigned will be used, and proto files will
2303
+ not be able to override it.
2304
+ """
2305
+
2306
+
2307
+ default_message_pool.register_message("google.protobuf", "FieldOptions.FeatureSupport", FieldOptionsFeatureSupport)
2308
+
2309
+
1664
2310
  @dataclass(eq=False, repr=False)
1665
2311
  class FileDescriptorProto(betterproto2.Message):
1666
2312
  """
@@ -1717,7 +2363,14 @@ class FileDescriptorProto(betterproto2.Message):
1717
2363
  syntax: "str" = betterproto2.field(12, betterproto2.TYPE_STRING)
1718
2364
  """
1719
2365
  The syntax of the proto file.
1720
- The supported values are "proto2" and "proto3".
2366
+ The supported values are "proto2", "proto3", and "editions".
2367
+
2368
+ If `edition` is present, this value must be "editions".
2369
+ """
2370
+
2371
+ edition: "Edition" = betterproto2.field(14, betterproto2.TYPE_ENUM, default_factory=lambda: Edition(0))
2372
+ """
2373
+ The edition of the proto file.
1721
2374
  """
1722
2375
 
1723
2376
 
@@ -1807,12 +2460,16 @@ class FileOptions(betterproto2.Message):
1807
2460
 
1808
2461
  java_string_check_utf8: "bool" = betterproto2.field(27, betterproto2.TYPE_BOOL)
1809
2462
  """
1810
- If set true, then the Java2 code generator will generate code that
1811
- throws an exception whenever an attempt is made to assign a non-UTF-8
1812
- byte sequence to a string field.
1813
- Message reflection will do the same.
1814
- However, an extension field still accepts non-UTF-8 byte sequences.
1815
- This option has no effect on when used with the lite runtime.
2463
+ A proto2 file can set this to true to opt in to UTF-8 checking for Java,
2464
+ which will throw an exception if invalid UTF-8 is parsed from the wire or
2465
+ assigned to a string field.
2466
+
2467
+ TODO: clarify exactly what kinds of field types this option
2468
+ applies to, and update these docs accordingly.
2469
+
2470
+ Proto3 files already perform these checks. Setting the option explicitly to
2471
+ false has no effect: it cannot be used to opt proto3 files out of UTF-8
2472
+ checks.
1816
2473
  """
1817
2474
 
1818
2475
  optimize_for: "FileOptionsOptimizeMode" = betterproto2.field(
@@ -1846,8 +2503,6 @@ class FileOptions(betterproto2.Message):
1846
2503
 
1847
2504
  py_generic_services: "bool" = betterproto2.field(18, betterproto2.TYPE_BOOL)
1848
2505
 
1849
- php_generic_services: "bool" = betterproto2.field(42, betterproto2.TYPE_BOOL)
1850
-
1851
2506
  deprecated: "bool" = betterproto2.field(23, betterproto2.TYPE_BOOL)
1852
2507
  """
1853
2508
  Is this file deprecated?
@@ -1908,6 +2563,11 @@ class FileOptions(betterproto2.Message):
1908
2563
  determining the ruby package.
1909
2564
  """
1910
2565
 
2566
+ features: "FeatureSet | None" = betterproto2.field(50, betterproto2.TYPE_MESSAGE, optional=True)
2567
+ """
2568
+ Any features defined in the specific edition.
2569
+ """
2570
+
1911
2571
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
1912
2572
  999, betterproto2.TYPE_MESSAGE, repeated=True
1913
2573
  )
@@ -1939,10 +2599,10 @@ class FloatValue(betterproto2.Message):
1939
2599
  """
1940
2600
 
1941
2601
  @classmethod
1942
- def from_dict(cls, value):
2602
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
1943
2603
  if isinstance(value, float):
1944
2604
  return FloatValue(value=value)
1945
- return super().from_dict(value)
2605
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
1946
2606
 
1947
2607
  def to_dict(
1948
2608
  self,
@@ -2004,10 +2664,14 @@ class GeneratedCodeInfoAnnotation(betterproto2.Message):
2004
2664
  end: "int" = betterproto2.field(4, betterproto2.TYPE_INT32)
2005
2665
  """
2006
2666
  Identifies the ending offset in bytes in the generated code that
2007
- relates to the identified offset. The end offset should be one past
2667
+ relates to the identified object. The end offset should be one past
2008
2668
  the last relevant byte (so the length of the text = end - begin).
2009
2669
  """
2010
2670
 
2671
+ semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto2.field(
2672
+ 5, betterproto2.TYPE_ENUM, default_factory=lambda: GeneratedCodeInfoAnnotationSemantic(0)
2673
+ )
2674
+
2011
2675
 
2012
2676
  default_message_pool.register_message("google.protobuf", "GeneratedCodeInfo.Annotation", GeneratedCodeInfoAnnotation)
2013
2677
 
@@ -2026,10 +2690,10 @@ class Int32Value(betterproto2.Message):
2026
2690
  """
2027
2691
 
2028
2692
  @classmethod
2029
- def from_dict(cls, value):
2693
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2030
2694
  if isinstance(value, int):
2031
2695
  return Int32Value(value=value)
2032
- return super().from_dict(value)
2696
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
2033
2697
 
2034
2698
  def to_dict(
2035
2699
  self,
@@ -2065,10 +2729,10 @@ class Int64Value(betterproto2.Message):
2065
2729
  """
2066
2730
 
2067
2731
  @classmethod
2068
- def from_dict(cls, value):
2732
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2069
2733
  if isinstance(value, int):
2070
2734
  return Int64Value(value=value)
2071
- return super().from_dict(value)
2735
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
2072
2736
 
2073
2737
  def to_dict(
2074
2738
  self,
@@ -2103,6 +2767,22 @@ class ListValue(betterproto2.Message):
2103
2767
  Repeated field of dynamically typed values.
2104
2768
  """
2105
2769
 
2770
+ @classmethod
2771
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2772
+ return cls(values=[Value.from_dict(v) for v in value])
2773
+
2774
+ def to_dict(
2775
+ self,
2776
+ *,
2777
+ output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
2778
+ casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
2779
+ include_default_values: bool = False,
2780
+ ) -> dict[str, typing.Any] | typing.Any:
2781
+ # If the output format is PYTHON, we should have kept the wrapped type without building the real class
2782
+ assert output_format == betterproto2.OutputFormat.PROTO_JSON
2783
+
2784
+ return [value.to_dict() for value in self.values]
2785
+
2106
2786
 
2107
2787
  default_message_pool.register_message("google.protobuf", "ListValue", ListValue)
2108
2788
 
@@ -2171,6 +2851,25 @@ class MessageOptions(betterproto2.Message):
2171
2851
  parser.
2172
2852
  """
2173
2853
 
2854
+ deprecated_legacy_json_field_conflicts: "bool" = betterproto2.field(11, betterproto2.TYPE_BOOL)
2855
+ """
2856
+ Enable the legacy handling of JSON field name conflicts. This lowercases
2857
+ and strips underscored from the fields before comparison in proto3 only.
2858
+ The new behavior takes `json_name` into account and applies to proto2 as
2859
+ well.
2860
+
2861
+ This should only be used as a temporary measure against broken builds due
2862
+ to the change in behavior for JSON field name conflicts.
2863
+
2864
+ TODO This is legacy behavior we plan to remove once downstream
2865
+ teams have had time to migrate.
2866
+ """
2867
+
2868
+ features: "FeatureSet | None" = betterproto2.field(12, betterproto2.TYPE_MESSAGE, optional=True)
2869
+ """
2870
+ Any features defined in the specific edition.
2871
+ """
2872
+
2174
2873
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
2175
2874
  999, betterproto2.TYPE_MESSAGE, repeated=True
2176
2875
  )
@@ -2178,6 +2877,11 @@ class MessageOptions(betterproto2.Message):
2178
2877
  The parser stores options it doesn't recognize here. See above.
2179
2878
  """
2180
2879
 
2880
+ def __post_init__(self) -> None:
2881
+ super().__post_init__()
2882
+ if self.is_set("deprecated_legacy_json_field_conflicts"):
2883
+ warnings.warn("MessageOptions.deprecated_legacy_json_field_conflicts is deprecated", DeprecationWarning)
2884
+
2181
2885
 
2182
2886
  default_message_pool.register_message("google.protobuf", "MessageOptions", MessageOptions)
2183
2887
 
@@ -2278,6 +2982,11 @@ class MethodOptions(betterproto2.Message):
2278
2982
  34, betterproto2.TYPE_ENUM, default_factory=lambda: MethodOptionsIdempotencyLevel(0)
2279
2983
  )
2280
2984
 
2985
+ features: "FeatureSet | None" = betterproto2.field(35, betterproto2.TYPE_MESSAGE, optional=True)
2986
+ """
2987
+ Any features defined in the specific edition.
2988
+ """
2989
+
2281
2990
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
2282
2991
  999, betterproto2.TYPE_MESSAGE, repeated=True
2283
2992
  )
@@ -2403,6 +3112,11 @@ default_message_pool.register_message("google.protobuf", "OneofDescriptorProto",
2403
3112
 
2404
3113
  @dataclass(eq=False, repr=False)
2405
3114
  class OneofOptions(betterproto2.Message):
3115
+ features: "FeatureSet | None" = betterproto2.field(1, betterproto2.TYPE_MESSAGE, optional=True)
3116
+ """
3117
+ Any features defined in the specific edition.
3118
+ """
3119
+
2406
3120
  uninterpreted_option: "list[UninterpretedOption]" = betterproto2.field(
2407
3121
  999, betterproto2.TYPE_MESSAGE, repeated=True
2408
3122
  )
@@ -2459,6 +3173,11 @@ default_message_pool.register_message("google.protobuf", "ServiceDescriptorProto
2459
3173
 
2460
3174
  @dataclass(eq=False, repr=False)
2461
3175
  class ServiceOptions(betterproto2.Message):
3176
+ features: "FeatureSet | None" = betterproto2.field(34, betterproto2.TYPE_MESSAGE, optional=True)
3177
+ """
3178
+ Any features defined in the specific edition.
3179
+ """
3180
+
2462
3181
  deprecated: "bool" = betterproto2.field(33, betterproto2.TYPE_BOOL)
2463
3182
  """
2464
3183
  Note: Field numbers 1 through 32 are reserved for Google's internal RPC
@@ -2552,7 +3271,7 @@ class SourceCodeInfoLocation(betterproto2.Message):
2552
3271
  location.
2553
3272
 
2554
3273
  Each element is a field number or an index. They form a path from
2555
- the root FileDescriptorProto to the place where the definition occurs.
3274
+ the root FileDescriptorProto to the place where the definition appears.
2556
3275
  For example, this path:
2557
3276
  [ 4, 3, 2, 7, 1 ]
2558
3277
  refers to:
@@ -2672,10 +3391,10 @@ class StringValue(betterproto2.Message):
2672
3391
  """
2673
3392
 
2674
3393
  @classmethod
2675
- def from_dict(cls, value):
3394
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2676
3395
  if isinstance(value, str):
2677
3396
  return StringValue(value=value)
2678
- return super().from_dict(value)
3397
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
2679
3398
 
2680
3399
  def to_dict(
2681
3400
  self,
@@ -2717,6 +3436,34 @@ class Struct(betterproto2.Message):
2717
3436
  Unordered map of dynamically typed values.
2718
3437
  """
2719
3438
 
3439
+ @classmethod
3440
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
3441
+ assert isinstance(value, dict)
3442
+
3443
+ fields: dict[str, Value] = {}
3444
+
3445
+ for key, val in value.items():
3446
+ fields[key] = Value.from_dict(val)
3447
+
3448
+ return cls(fields=fields)
3449
+
3450
+ def to_dict(
3451
+ self,
3452
+ *,
3453
+ output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
3454
+ casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
3455
+ include_default_values: bool = False,
3456
+ ) -> dict[str, typing.Any] | typing.Any:
3457
+ # If the output format is PYTHON, we should have kept the wrapped type without building the real class
3458
+ assert output_format == betterproto2.OutputFormat.PROTO_JSON
3459
+
3460
+ return {
3461
+ key: value.to_dict(
3462
+ output_format=output_format, casing=casing, include_default_values=include_default_values
3463
+ )
3464
+ for key, value in self.fields.items()
3465
+ }
3466
+
2720
3467
 
2721
3468
  default_message_pool.register_message("google.protobuf", "Struct", Struct)
2722
3469
 
@@ -2811,7 +3558,7 @@ class Timestamp(betterproto2.Message):
2811
3558
  [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
2812
3559
  the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
2813
3560
  the Joda Time's [`ISODateTimeFormat.dateTime()`](
2814
- http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
3561
+ http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
2815
3562
  ) to obtain a formatter capable of generating timestamps in this format.
2816
3563
  """
2817
3564
 
@@ -2876,13 +3623,13 @@ class Timestamp(betterproto2.Message):
2876
3623
  return f"{result}.{nanos:09d}"
2877
3624
 
2878
3625
  @classmethod
2879
- def from_dict(cls, value):
3626
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2880
3627
  if isinstance(value, str):
2881
3628
  dt = dateutil.parser.isoparse(value)
2882
3629
  dt = dt.astimezone(datetime.timezone.utc)
2883
3630
  return Timestamp.from_datetime(dt)
2884
3631
 
2885
- return super().from_dict(value)
3632
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
2886
3633
 
2887
3634
  def to_dict(
2888
3635
  self,
@@ -2943,6 +3690,11 @@ class Type(betterproto2.Message):
2943
3690
  The source syntax.
2944
3691
  """
2945
3692
 
3693
+ edition: "str" = betterproto2.field(7, betterproto2.TYPE_STRING)
3694
+ """
3695
+ The source edition string, only valid when syntax is SYNTAX_EDITIONS.
3696
+ """
3697
+
2946
3698
 
2947
3699
  default_message_pool.register_message("google.protobuf", "Type", Type)
2948
3700
 
@@ -2961,10 +3713,10 @@ class UInt32Value(betterproto2.Message):
2961
3713
  """
2962
3714
 
2963
3715
  @classmethod
2964
- def from_dict(cls, value):
3716
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
2965
3717
  if isinstance(value, int):
2966
3718
  return UInt32Value(value=value)
2967
- return super().from_dict(value)
3719
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
2968
3720
 
2969
3721
  def to_dict(
2970
3722
  self,
@@ -3000,10 +3752,10 @@ class UInt64Value(betterproto2.Message):
3000
3752
  """
3001
3753
 
3002
3754
  @classmethod
3003
- def from_dict(cls, value):
3755
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
3004
3756
  if isinstance(value, int):
3005
3757
  return UInt64Value(value=value)
3006
- return super().from_dict(value)
3758
+ return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
3007
3759
 
3008
3760
  def to_dict(
3009
3761
  self,
@@ -3120,5 +3872,48 @@ class Value(betterproto2.Message):
3120
3872
  Represents a repeated `Value`.
3121
3873
  """
3122
3874
 
3875
+ @classmethod
3876
+ def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
3877
+ match value:
3878
+ case bool() as b:
3879
+ return cls(bool_value=b)
3880
+ case int() | float() as num:
3881
+ return cls(number_value=num)
3882
+ case str() as s:
3883
+ return cls(string_value=s)
3884
+ case list() as l:
3885
+ return cls(list_value=ListValue.from_dict(l))
3886
+ case dict() as d:
3887
+ return cls(struct_value=Struct.from_dict(d))
3888
+ case None:
3889
+ return cls(null_value=NullValue.NULL_VALUE)
3890
+ raise ValueError(f"Unknown value type: {type(value)}")
3891
+
3892
+ def to_dict(
3893
+ self,
3894
+ *,
3895
+ output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
3896
+ casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
3897
+ include_default_values: bool = False,
3898
+ ) -> dict[str, typing.Any] | typing.Any:
3899
+ # If the output format is PYTHON, we should have kept the wrapped type without building the real class
3900
+ assert output_format == betterproto2.OutputFormat.PROTO_JSON
3901
+
3902
+ match self:
3903
+ case Value(null_value=NullValue.NULL_VALUE):
3904
+ return None
3905
+ case Value(bool_value=bool(b)):
3906
+ return b
3907
+ case Value(number_value=int(num)) | Value(number_value=float(num)):
3908
+ return num
3909
+ case Value(string_value=str(s)):
3910
+ return s
3911
+ case Value(list_value=ListValue(values=l)):
3912
+ return [v.to_dict() for v in l]
3913
+ case Value(struct_value=Struct(fields=f)):
3914
+ return {k: v.to_dict() for k, v in f.items()}
3915
+
3916
+ raise ValueError("Invalid value")
3917
+
3123
3918
 
3124
3919
  default_message_pool.register_message("google.protobuf", "Value", Value)