fix: strip trailing _ from field mask paths (#228)
diff --git a/google/api_core/protobuf_helpers.py b/google/api_core/protobuf_helpers.py
index 365ef25..8aff79a 100644
--- a/google/api_core/protobuf_helpers.py
+++ b/google/api_core/protobuf_helpers.py
@@ -357,6 +357,13 @@
def _get_path(current, name):
+ # gapic-generator-python appends underscores to field names
+ # that collide with python keywords.
+ # `_` is stripped away as it is not possible to
+ # natively define a field with a trailing underscore in protobuf.
+ # APIs will reject field masks if fields have trailing underscores.
+ # See https://github.com/googleapis/python-api-core/issues/227
+ name = name.rstrip("_")
if not current:
return name
return "%s.%s" % (current, name)
diff --git a/noxfile.py b/noxfile.py
index 2560992..2f11137 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -98,9 +98,10 @@
]
pytest_args.extend(session.posargs)
- # Inject AsyncIO content, if version >= 3.6.
+ # Inject AsyncIO content and proto-plus, if version >= 3.6.
+ # proto-plus is needed for a field mask test in test_protobuf_helpers.py
if _greater_or_equal_than_36(session.python):
- session.install("asyncmock", "pytest-asyncio")
+ session.install("asyncmock", "pytest-asyncio", "proto-plus")
pytest_args.append("--cov=tests.asyncio")
pytest_args.append(os.path.join("tests", "asyncio"))
diff --git a/tests/unit/test_protobuf_helpers.py b/tests/unit/test_protobuf_helpers.py
index db97238..3df45df 100644
--- a/tests/unit/test_protobuf_helpers.py
+++ b/tests/unit/test_protobuf_helpers.py
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import sys
+
import pytest
from google.api import http_pb2
@@ -472,3 +474,45 @@
"alpha",
"red",
]
+
+
+@pytest.mark.skipif(
+ sys.version_info.major == 2,
+ reason="Field names with trailing underscores can only be created"
+ "through proto-plus, which is Python 3 only.",
+)
+def test_field_mask_ignore_trailing_underscore():
+ import proto
+
+ class Foo(proto.Message):
+ type_ = proto.Field(proto.STRING, number=1)
+ input_config = proto.Field(proto.STRING, number=2)
+
+ modified = Foo(type_="bar", input_config="baz")
+
+ assert sorted(protobuf_helpers.field_mask(None, Foo.pb(modified)).paths) == [
+ "input_config",
+ "type",
+ ]
+
+
+@pytest.mark.skipif(
+ sys.version_info.major == 2,
+ reason="Field names with trailing underscores can only be created"
+ "through proto-plus, which is Python 3 only.",
+)
+def test_field_mask_ignore_trailing_underscore_with_nesting():
+ import proto
+
+ class Bar(proto.Message):
+ class Baz(proto.Message):
+ input_config = proto.Field(proto.STRING, number=1)
+
+ type_ = proto.Field(Baz, number=1)
+
+ modified = Bar()
+ modified.type_.input_config = "foo"
+
+ assert sorted(protobuf_helpers.field_mask(None, Bar.pb(modified)).paths) == [
+ "type.input_config",
+ ]