Skip to content

Commit 1dc8a17

Browse files
committed
Remove emission of python keywords.
Added testing for this behavior. Fixes #73. See #73 for details.
1 parent b0a97c4 commit 1dc8a17

File tree

3 files changed

+132
-9
lines changed

3 files changed

+132
-9
lines changed

proto/test/proto/test.proto

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,54 @@ message Simple2 {
4848
required string a_string = 1;
4949
}
5050

51+
message PythonReservedKeywords {
52+
enum finally {
53+
continue = 1;
54+
}
55+
// protoc python generator actually generates invalid code for this, so not testing
56+
//message lambda {
57+
// optional int64 continue = 1;
58+
//}
59+
60+
required int64 from = 1;
61+
optional Simple2 in = 2;
62+
optional finally is = 3;
63+
optional int64 for = 5;
64+
optional int64 try = 6;
65+
optional int64 def = 7;
66+
optional int64 nonlocal = 8;
67+
optional int64 while = 9;
68+
optional int64 and = 10;
69+
optional int64 del = 11;
70+
optional int64 global = 12;
71+
optional int64 not = 13;
72+
optional int64 with = 14;
73+
optional int64 as = 15;
74+
optional int64 elif = 16;
75+
optional int64 if = 17;
76+
optional int64 or = 18;
77+
optional int64 yield = 19;
78+
optional int64 assert = 20;
79+
optional int64 else = 21;
80+
optional int64 import = 22;
81+
optional int64 pass = 23;
82+
optional int64 break = 24;
83+
optional int64 except = 25;
84+
optional int64 raise = 26;
85+
optional int64 False = 27;
86+
optional int64 None = 28;
87+
optional int64 True = 29;
88+
}
89+
90+
// Do one with just one arg - to make sure it's syntactically correct
91+
message PythonReservedKeywordsSmall {
92+
required int64 from = 1;
93+
}
94+
95+
service PythonReservedKeywordsService {
96+
rpc lambda(Simple1) returns (Simple2) {}
97+
}
98+
5199
option py_generic_services = true;
52100
service ATestService {
53101
rpc Echo(Simple1) returns (Simple2) {}

python/protoc-gen-mypy

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,42 @@ else:
4040
GENERATED = "@ge" + "nerated" # So phabricator doesn't think this file is generated
4141
HEADER = "# {} by generate_proto_mypy_stubs.py. Do not edit!\n".format(GENERATED)
4242

43+
# See https://github.com/dropbox/mypy-protobuf/issues/73 for details
44+
PYTHON_RESERVED = set([
45+
'False',
46+
'None',
47+
'True',
48+
'and',
49+
'as',
50+
'assert',
51+
'break',
52+
'continue',
53+
'def',
54+
'del',
55+
'elif',
56+
'else',
57+
'except',
58+
'finally',
59+
'for',
60+
'from',
61+
'global',
62+
'if',
63+
'import',
64+
'in',
65+
'is',
66+
'lambda',
67+
'nonlocal',
68+
'not',
69+
'or',
70+
'pass',
71+
'raise',
72+
'return',
73+
'try',
74+
'while',
75+
'with',
76+
'yield'
77+
])
78+
4379
class PkgWriter(object):
4480
"""Writes a single pyi file"""
4581

@@ -111,7 +147,7 @@ class PkgWriter(object):
111147
def write_enums(self, enums, prefix=''):
112148
# type: (Iterable[d.EnumDescriptorProto], Text) -> None
113149
l = self._write_line
114-
for enum in enums:
150+
for enum in [e for e in enums if e.name not in PYTHON_RESERVED]:
115151
l("class {}(int):", enum.name)
116152
with self._indent():
117153
l("DESCRIPTOR: {} = ...",
@@ -142,17 +178,18 @@ class PkgWriter(object):
142178
l = self._write_line
143179
message_class = self._import("google.protobuf.message", "Message")
144180

145-
for desc in messages:
181+
for desc in [m for m in messages if m.name not in PYTHON_RESERVED]:
146182
self.locals.add(desc.name)
147183
qualified_name = prefix + desc.name
148184
l("class {}({}):", desc.name, message_class)
149185
with self._indent():
150186
# Nested enums/messages
151187
self.write_enums(desc.enum_type, qualified_name + ".")
152188
self.write_messages(desc.nested_type, qualified_name + ".")
189+
fields = [f for f in desc.field if f.name not in PYTHON_RESERVED]
153190

154191
# Scalar fields
155-
for field in [f for f in desc.field if is_scalar(f)]:
192+
for field in [f for f in fields if is_scalar(f)]:
156193
if field.label == d.FieldDescriptorProto.LABEL_REPEATED:
157194
container = self._import("google.protobuf.internal.containers", "RepeatedScalarFieldContainer")
158195
l("{} = ... # type: {}[{}]", field.name, container, self.python_type(field))
@@ -161,7 +198,7 @@ class PkgWriter(object):
161198
l("")
162199

163200
# Getters for non-scalar fields
164-
for field in [f for f in desc.field if not is_scalar(f)]:
201+
for field in [f for f in fields if not is_scalar(f)]:
165202
l("@property")
166203
if field.label == d.FieldDescriptorProto.LABEL_REPEATED:
167204
msg = self.descriptors.messages[field.type_name]
@@ -179,14 +216,14 @@ class PkgWriter(object):
179216
# Constructor
180217
l("def __init__(self,")
181218
with self._indent():
182-
if len(desc.field) > 0:
219+
if len(fields) > 0:
183220
# Only positional args allowed
184221
# See https://github.com/dropbox/mypy-protobuf/issues/71
185222
l("*,")
186223
# Required args
187-
for field in [f for f in desc.field if f.label == d.FieldDescriptorProto.LABEL_REQUIRED]:
224+
for field in [f for f in fields if f.label == d.FieldDescriptorProto.LABEL_REQUIRED]:
188225
l("{} : {},", field.name, self.python_type(field))
189-
for field in [f for f in desc.field if f.label != d.FieldDescriptorProto.LABEL_REQUIRED]:
226+
for field in [f for f in fields if f.label != d.FieldDescriptorProto.LABEL_REQUIRED]:
190227
if field.label == d.FieldDescriptorProto.LABEL_REPEATED:
191228
if field.type_name in self.descriptors.messages and self.descriptors.messages[field.type_name].options.map_entry:
192229
msg = self.descriptors.messages[field.type_name]
@@ -290,7 +327,10 @@ class PkgWriter(object):
290327
def write_methods(self, service, is_abstract):
291328
# type: (d.ServiceDescriptorProto, bool) -> None
292329
l = self._write_line
293-
for method in service.method:
330+
methods = [m for m in service.method if m.name not in PYTHON_RESERVED]
331+
if not methods:
332+
l("pass")
333+
for method in methods:
294334
if is_abstract:
295335
l("@{}", self._import("abc", "abstractmethod"))
296336
l("def {}(self,", method.name)
@@ -306,7 +346,7 @@ class PkgWriter(object):
306346
def write_services(self, services):
307347
# type: (Iterable[d.ServiceDescriptorProto]) -> None
308348
l = self._write_line
309-
for service in services:
349+
for service in [s for s in services if s.name not in PYTHON_RESERVED]:
310350
# The service definition interface
311351
l("class {}({}, metaclass={}):", service.name, self._import("google.protobuf.service", "Service"), self._import("abc", "ABCMeta"))
312352
with self._indent():

test/proto/test_pb2.pyi.expected

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,41 @@ class Simple2(google___protobuf___message___Message):
180180
def HasField(self, field_name: typing_extensions___Literal[u"a_string",b"a_string"]) -> bool: ...
181181
def ClearField(self, field_name: typing_extensions___Literal[u"a_string",b"a_string"]) -> None: ...
182182

183+
class PythonReservedKeywords(google___protobuf___message___Message):
184+
185+
def __init__(self,
186+
) -> None: ...
187+
@classmethod
188+
def FromString(cls, s: bytes) -> PythonReservedKeywords: ...
189+
def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
190+
def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
191+
if sys.version_info >= (3,):
192+
def HasField(self, field_name: typing_extensions___Literal[u"False",u"None",u"True",u"and",u"as",u"assert",u"break",u"def",u"del",u"elif",u"else",u"except",u"for",u"from",u"global",u"if",u"import",u"in",u"is",u"nonlocal",u"not",u"or",u"pass",u"raise",u"try",u"while",u"with",u"yield"]) -> bool: ...
193+
def ClearField(self, field_name: typing_extensions___Literal[u"False",u"None",u"True",u"and",u"as",u"assert",u"break",u"def",u"del",u"elif",u"else",u"except",u"for",u"from",u"global",u"if",u"import",u"in",u"is",u"nonlocal",u"not",u"or",u"pass",u"raise",u"try",u"while",u"with",u"yield"]) -> None: ...
194+
else:
195+
def HasField(self, field_name: typing_extensions___Literal[u"False",b"False",u"None",b"None",u"True",b"True",u"and",b"and",u"as",b"as",u"assert",b"assert",u"break",b"break",u"def",b"def",u"del",b"del",u"elif",b"elif",u"else",b"else",u"except",b"except",u"for",b"for",u"from",b"from",u"global",b"global",u"if",b"if",u"import",b"import",u"in",b"in",u"is",b"is",u"nonlocal",b"nonlocal",u"not",b"not",u"or",b"or",u"pass",b"pass",u"raise",b"raise",u"try",b"try",u"while",b"while",u"with",b"with",u"yield",b"yield"]) -> bool: ...
196+
def ClearField(self, field_name: typing_extensions___Literal[u"False",b"False",u"None",b"None",u"True",b"True",u"and",b"and",u"as",b"as",u"assert",b"assert",u"break",b"break",u"def",b"def",u"del",b"del",u"elif",b"elif",u"else",b"else",u"except",b"except",u"for",b"for",u"from",b"from",u"global",b"global",u"if",b"if",u"import",b"import",u"in",b"in",u"is",b"is",u"nonlocal",b"nonlocal",u"not",b"not",u"or",b"or",u"pass",b"pass",u"raise",b"raise",u"try",b"try",u"while",b"while",u"with",b"with",u"yield",b"yield"]) -> None: ...
197+
198+
class PythonReservedKeywordsSmall(google___protobuf___message___Message):
199+
200+
def __init__(self,
201+
) -> None: ...
202+
@classmethod
203+
def FromString(cls, s: bytes) -> PythonReservedKeywordsSmall: ...
204+
def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
205+
def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
206+
if sys.version_info >= (3,):
207+
def HasField(self, field_name: typing_extensions___Literal[u"from"]) -> bool: ...
208+
def ClearField(self, field_name: typing_extensions___Literal[u"from"]) -> None: ...
209+
else:
210+
def HasField(self, field_name: typing_extensions___Literal[u"from",b"from"]) -> bool: ...
211+
def ClearField(self, field_name: typing_extensions___Literal[u"from",b"from"]) -> None: ...
212+
213+
class PythonReservedKeywordsService(google___protobuf___service___Service, metaclass=abc___ABCMeta):
214+
pass
215+
class PythonReservedKeywordsService_Stub(PythonReservedKeywordsService):
216+
def __init__(self, rpc_channel: google___protobuf___service___RpcChannel) -> None: ...
217+
pass
183218
class ATestService(google___protobuf___service___Service, metaclass=abc___ABCMeta):
184219
@abc___abstractmethod
185220
def Echo(self,

0 commit comments

Comments
 (0)