Skip to content

Commit f85bf45

Browse files
Add handling for protobuf==7 (#429)
`protobuf` v7 was released last week, which dropped support for some of the APIs that we use for checking field types. This fixes those accesses so that we can still support all the way back to v5. Fixes #410. Ref: https://pypi.org/project/protobuf/ Ref: https://github.com/protocolbuffers/protobuf/releases/tag/v34.0
1 parent 5d89a7e commit f85bf45

File tree

2 files changed

+28
-21
lines changed

2 files changed

+28
-21
lines changed

protovalidate/internal/rules.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@
2424
from buf.validate import validate_pb2
2525
from protovalidate.internal.cel_field_presence import InterpretedRunner, in_has
2626

27+
# protobuf 7+ removed FieldDescriptor.label / LABEL_REPEATED in favour of is_repeated.
28+
if hasattr(descriptor.FieldDescriptor, "is_repeated"):
29+
30+
def _is_repeated(field: descriptor.FieldDescriptor) -> bool:
31+
return field.is_repeated # type: ignore[attr-defined]
32+
33+
else:
34+
35+
def _is_repeated(field: descriptor.FieldDescriptor) -> bool:
36+
return field.label == descriptor.FieldDescriptor.LABEL_REPEATED # type: ignore[attr-defined]
37+
2738

2839
class CompilationError(Exception):
2940
pass
@@ -155,7 +166,7 @@ def _scalar_field_value_to_cel(val: typing.Any, field: descriptor.FieldDescripto
155166

156167

157168
def _field_value_to_cel(val: typing.Any, field: descriptor.FieldDescriptor) -> celtypes.Value:
158-
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
169+
if _is_repeated(field):
159170
if field.message_type is not None and field.message_type.GetOptions().map_entry:
160171
return _map_field_value_to_cel(val, field)
161172
return _repeated_field_value_to_cel(val, field)
@@ -165,7 +176,7 @@ def _field_value_to_cel(val: typing.Any, field: descriptor.FieldDescriptor) -> c
165176
def _is_empty_field(msg: message.Message, field: descriptor.FieldDescriptor) -> bool:
166177
if field.has_presence:
167178
return not _proto_message_has_field(msg, field)
168-
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
179+
if _is_repeated(field):
169180
return len(_proto_message_get_field(msg, field)) == 0
170181
return _proto_message_get_field(msg, field) == field.default_value
171182

@@ -194,7 +205,7 @@ def _map_field_to_cel(msg: message.Message, field: descriptor.FieldDescriptor) -
194205

195206

196207
def field_to_cel(msg: message.Message, field: descriptor.FieldDescriptor) -> celtypes.Value:
197-
if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
208+
if _is_repeated(field):
198209
return _repeated_field_to_cel(msg, field)
199210
elif field.message_type is not None and not _proto_message_has_field(msg, field):
200211
return None
@@ -492,19 +503,15 @@ def check_field_type(field: descriptor.FieldDescriptor, expected: int, wrapper_n
492503

493504

494505
def _is_map(field: descriptor.FieldDescriptor):
495-
return (
496-
field.label == descriptor.FieldDescriptor.LABEL_REPEATED
497-
and field.message_type is not None
498-
and field.message_type.GetOptions().map_entry
499-
)
506+
return _is_repeated(field) and field.message_type is not None and field.message_type.GetOptions().map_entry
500507

501508

502509
def _is_list(field: descriptor.FieldDescriptor):
503-
return field.label == descriptor.FieldDescriptor.LABEL_REPEATED and not _is_map(field)
510+
return _is_repeated(field) and not _is_map(field)
504511

505512

506513
def _zero_value(field: descriptor.FieldDescriptor):
507-
if field.message_type is not None and field.label != descriptor.FieldDescriptor.LABEL_REPEATED:
514+
if field.message_type is not None and not _is_repeated(field):
508515
return _field_value_to_cel(message_factory.GetMessageClass(field.message_type)(), field)
509516
else:
510517
return _field_value_to_cel(field.default_value, field)
@@ -1030,7 +1037,7 @@ def _new_field_rule(
10301037
field: descriptor.FieldDescriptor,
10311038
rules: validate_pb2.FieldRules,
10321039
) -> FieldRules:
1033-
if field.label != descriptor.FieldDescriptor.LABEL_REPEATED:
1040+
if not _is_repeated(field):
10341041
return self._new_scalar_field_rule(field, rules)
10351042
if field.message_type is not None and field.message_type.GetOptions().map_entry:
10361043
key_rules = None
@@ -1084,7 +1091,7 @@ def _new_rules(self, desc: descriptor.Descriptor) -> list[Rules]:
10841091
if value_field.type != descriptor.FieldDescriptor.TYPE_MESSAGE:
10851092
continue
10861093
result.append(MapValMsgRule(self, field, key_field, value_field))
1087-
elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
1094+
elif _is_repeated(field):
10881095
result.append(RepeatedMsgRule(self, field))
10891096
else:
10901097
result.append(SubMsgRule(self, field))

uv.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)