Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix generated code for enums with name conflict with EnumTypeWrapper… #246

Merged
merged 1 commit into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ test_message_option: google.protobuf.descriptor.FieldDescriptor = ...
test_message_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, typing.Text] = ...
```
- Now requires [types-protobuf](https://pypi.org/project/types-protobuf/) 3.17.1
- Fix [#238](https://github.com/dropbox/mypy-protobuf/issues/238) - handling enum variants that name conflict with EnumTypeWrapper methods


## 2.6
Expand Down
21 changes: 17 additions & 4 deletions mypy_protobuf/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@
"yield",
}

PROTO_ENUM_RESERVED = {
"Name",
"Value",
"keys",
"values",
"items",
}


def _mangle_global_identifier(name: str) -> str:
"""
Expand Down Expand Up @@ -214,8 +222,10 @@ def _write_line(self, line: str, *args: Any) -> None:
else:
self.lines.append(self.indent + line.format(*args))

def write_enum_values(self, enum: d.EnumDescriptorProto, value_type: str) -> None:
for val in enum.value:
def write_enum_values(
self, values: Sequence[d.EnumValueDescriptorProto], value_type: str
) -> None:
for val in values:
if val.name in PYTHON_RESERVED:
continue

Expand Down Expand Up @@ -251,7 +261,7 @@ def write_enums(
l("{} = {}", _mangle_global_identifier(enum.name), enum.name)
l("")

self.write_enum_values(enum, prefix + enum.name + ".V")
self.write_enum_values(enum.value, prefix + enum.name + ".V")
l("")

# do a type-ignore to avoid the circular dependency. It's ugly.
Expand All @@ -271,7 +281,10 @@ def write_enums(
"DESCRIPTOR: {} = ...",
self._import("google.protobuf.descriptor", "EnumDescriptor"),
)
self.write_enum_values(enum, prefix + enum.name + ".V")
self.write_enum_values(
[v for v in enum.value if v.name not in PROTO_ENUM_RESERVED],
prefix + enum.name + ".V",
)
l("")

def write_messages(
Expand Down
12 changes: 12 additions & 0 deletions proto/testproto/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ enum OuterEnum {
BAR = 2;
}

enum NamingConflicts {
// Naming conflicts!
Name = 1;
Value = 2;
keys = 3;
values = 4;
items = 5;
// See https://github.com/protocolbuffers/protobuf/issues/8803
// proto itself generates broken code when DESCRIPTOR is there
// DESCRIPTOR = 8;
}

message Simple1 {
enum InnerEnum {
INNER1 = 1;
Expand Down
14 changes: 14 additions & 0 deletions test/generated/testproto/test_pb2.pyi.expected
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ class _OuterEnum(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Out
FOO = OuterEnum.V(1)
BAR = OuterEnum.V(2)

class NamingConflicts(metaclass=_NamingConflicts):
V = typing.NewType('V', builtins.int)

global___NamingConflicts = NamingConflicts

Name = NamingConflicts.V(1)
Value = NamingConflicts.V(2)
keys = NamingConflicts.V(3)
values = NamingConflicts.V(4)
items = NamingConflicts.V(5)

class _NamingConflicts(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[NamingConflicts.V], builtins.type): # type: ignore
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor = ...

class Simple1(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor = ...
class InnerEnum(metaclass=_InnerEnum):
Expand Down
9 changes: 9 additions & 0 deletions test/test_generated_mypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
Extensions1,
Extensions2,
FOO,
Name as NamingConflicts_Name,
NamingConflicts,
OuterEnum,
Simple1,
Simple2,
Expand Down Expand Up @@ -202,6 +204,13 @@ def test_enum():
assert OuterEnum.Value(u"BAR") == OuterEnum.Value(b"BAR")


def test_enum_naming_conflicts():
# type: () -> None
assert NamingConflicts.Name(NamingConflicts_Name) == "Name"
assert NamingConflicts.Value("Name") == 1
assert NamingConflicts_Name == 1


def test_has_field_proto2():
# type: () -> None
"""For HasField which is typed with Literal"""
Expand Down