Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

Commit 158ae99

Browse files
authored
fix: mitigate collisions in field names (#295)
* fix: mitigate collisions in field names * lint * add comment * address review feedback
1 parent 51e316e commit 158ae99

2 files changed

Lines changed: 53 additions & 6 deletions

File tree

proto/message.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,23 @@ def __init__(
527527
try:
528528
pb_type = self._meta.fields[key].pb_type
529529
except KeyError:
530-
if ignore_unknown_fields:
531-
continue
532-
533-
raise ValueError(
534-
"Unknown field for {}: {}".format(self.__class__.__name__, key)
535-
)
530+
# Underscores may be appended to field names
531+
# that collide with python or proto-plus keywords.
532+
# In case a key only exists with a `_` suffix, coerce the key
533+
# to include the `_` suffix. Is not possible to
534+
# natively define the same field with a trailing underscore in protobuf.
535+
# See related issue
536+
# https://github.com/googleapis/python-api-core/issues/227
537+
if f"{key}_" in self._meta.fields:
538+
key = f"{key}_"
539+
pb_type = self._meta.fields[key].pb_type
540+
else:
541+
if ignore_unknown_fields:
542+
continue
543+
544+
raise ValueError(
545+
"Unknown field for {}: {}".format(self.__class__.__name__, key)
546+
)
536547

537548
pb_value = marshal.to_proto(pb_type, value)
538549
if pb_value is not None:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import proto
16+
17+
18+
# Underscores may be appended to field names
19+
# that collide with python or proto-plus keywords.
20+
# In case a key only exists with a `_` suffix, coerce the key
21+
# to include the `_` suffix. Is not possible to
22+
# natively define the same field with a trailing underscore in protobuf.
23+
# See related issue
24+
# https://github.com/googleapis/python-api-core/issues/227
25+
def test_fields_mitigate_collision():
26+
class TestMessage(proto.Message):
27+
spam_ = proto.Field(proto.STRING, number=1)
28+
eggs = proto.Field(proto.STRING, number=2)
29+
30+
obj = TestMessage(spam_="has_spam")
31+
obj.eggs = "has_eggs"
32+
assert obj.spam_ == "has_spam"
33+
34+
# Test that `spam` is coerced to `spam_`
35+
modified_obj = TestMessage({"spam": "has_spam", "eggs": "has_eggs"})
36+
assert modified_obj.spam_ == "has_spam"

0 commit comments

Comments
 (0)