Index: third_party/protobuf/src/google/protobuf/compiler/python/python_generator.cc |
=================================================================== |
--- third_party/protobuf/src/google/protobuf/compiler/python/python_generator.cc (revision 216642) |
+++ third_party/protobuf/src/google/protobuf/compiler/python/python_generator.cc (working copy) |
@@ -52,6 +52,7 @@ |
#include <google/protobuf/descriptor.pb.h> |
#include <google/protobuf/stubs/common.h> |
+#include <google/protobuf/stubs/stringprintf.h> |
#include <google/protobuf/io/printer.h> |
#include <google/protobuf/descriptor.h> |
#include <google/protobuf/io/zero_copy_stream.h> |
@@ -106,6 +107,12 @@ |
const char kDescriptorKey[] = "DESCRIPTOR"; |
+// Does the file have top-level enums? |
+inline bool HasTopLevelEnums(const FileDescriptor *file) { |
+ return file->enum_type_count() > 0; |
+} |
+ |
+ |
// Should we generate generic services for this file? |
inline bool HasGenericServices(const FileDescriptor *file) { |
return file->service_count() > 0 && |
@@ -120,13 +127,21 @@ |
// TODO(robinson): Allow parameterization of Python version? |
printer->Print( |
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
- "\n" |
- "from google.protobuf import descriptor\n" |
- "from google.protobuf import message\n" |
- "from google.protobuf import reflection\n"); |
+ "# source: $filename$\n" |
+ "\n", |
+ "filename", file->name()); |
+ if (HasTopLevelEnums(file)) { |
+ printer->Print( |
+ "from google.protobuf.internal import enum_type_wrapper\n"); |
+ } |
+ printer->Print( |
+ "from google.protobuf import descriptor as _descriptor\n" |
+ "from google.protobuf import message as _message\n" |
+ "from google.protobuf import reflection as _reflection\n" |
+ ); |
if (HasGenericServices(file)) { |
printer->Print( |
- "from google.protobuf import service\n" |
+ "from google.protobuf import service as _service\n" |
"from google.protobuf import service_reflection\n"); |
} |
@@ -204,12 +219,12 @@ |
case FieldDescriptor::CPPTYPE_STRING: |
if (field.type() == FieldDescriptor::TYPE_STRING) { |
return "unicode(\"" + CEscape(field.default_value_string()) + |
- "\", \"utf-8\")"; |
+ "\", \"utf-8\")"; |
} else { |
return "\"" + CEscape(field.default_value_string()) + "\""; |
} |
- case FieldDescriptor::CPPTYPE_MESSAGE: |
- return "None"; |
+ case FieldDescriptor::CPPTYPE_MESSAGE: |
+ return "None"; |
} |
// (We could add a default case above but then we wouldn't get the nice |
// compiler warning when a new type is added.) |
@@ -270,6 +285,11 @@ |
// since they need to call static RegisterExtension() methods on these |
// classes. |
FixForeignFieldsInExtensions(); |
+ // Descriptor options may have custom extensions. These custom options |
+ // can only be successfully parsed after we register corresponding |
+ // extensions. Therefore we parse all options again here to recognize |
+ // custom options that may be unknown when we define the descriptors. |
+ FixAllDescriptorOptions(); |
if (HasGenericServices(file)) { |
PrintServices(); |
} |
@@ -288,6 +308,13 @@ |
module_name); |
} |
printer_->Print("\n"); |
+ |
+ // Print public imports. |
+ for (int i = 0; i < file_->public_dependency_count(); ++i) { |
+ string module_name = ModuleName(file_->public_dependency(i)->name()); |
+ printer_->Print("from $module$ import *\n", "module", module_name); |
+ } |
+ printer_->Print("\n"); |
} |
// Prints the single file descriptor for this file. |
@@ -297,7 +324,7 @@ |
m["name"] = file_->name(); |
m["package"] = file_->package(); |
const char file_descriptor_template[] = |
- "$descriptor_name$ = descriptor.FileDescriptor(\n" |
+ "$descriptor_name$ = _descriptor.FileDescriptor(\n" |
" name='$name$',\n" |
" package='$package$',\n"; |
printer_->Print(m, file_descriptor_template); |
@@ -321,6 +348,11 @@ |
for (int i = 0; i < file_->enum_type_count(); ++i) { |
const EnumDescriptor& enum_descriptor = *file_->enum_type(i); |
PrintEnum(enum_descriptor); |
+ printer_->Print("$name$ = " |
+ "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)", |
+ "name", enum_descriptor.name(), |
+ "descriptor_name", |
+ ModuleLevelDescriptorName(enum_descriptor)); |
printer_->Print("\n"); |
for (int j = 0; j < enum_descriptor.value_count(); ++j) { |
@@ -355,7 +387,7 @@ |
m["full_name"] = enum_descriptor.full_name(); |
m["file"] = kDescriptorKey; |
const char enum_descriptor_template[] = |
- "$descriptor_name$ = descriptor.EnumDescriptor(\n" |
+ "$descriptor_name$ = _descriptor.EnumDescriptor(\n" |
" name='$name$',\n" |
" full_name='$full_name$',\n" |
" filename=None,\n" |
@@ -436,7 +468,7 @@ |
descriptor.options().SerializeToString(&options_string); |
printer_->Print( |
- "$service_name$ = descriptor.ServiceDescriptor(\n", |
+ "$service_name$ = _descriptor.ServiceDescriptor(\n", |
"service_name", service_name); |
printer_->Indent(); |
map<string, string> m; |
@@ -459,7 +491,6 @@ |
printer_->Print("methods=[\n"); |
for (int i = 0; i < descriptor.method_count(); ++i) { |
const MethodDescriptor* method = descriptor.method(i); |
- string options_string; |
method->options().SerializeToString(&options_string); |
m.clear(); |
@@ -470,7 +501,7 @@ |
m["input_type"] = ModuleLevelDescriptorName(*(method->input_type())); |
m["output_type"] = ModuleLevelDescriptorName(*(method->output_type())); |
m["options_value"] = OptionsValue("MethodOptions", options_string); |
- printer_->Print("descriptor.MethodDescriptor(\n"); |
+ printer_->Print("_descriptor.MethodDescriptor(\n"); |
printer_->Indent(); |
printer_->Print( |
m, |
@@ -491,7 +522,7 @@ |
void Generator::PrintServiceClass(const ServiceDescriptor& descriptor) const { |
// Print the service. |
- printer_->Print("class $class_name$(service.Service):\n", |
+ printer_->Print("class $class_name$(_service.Service):\n", |
"class_name", descriptor.name()); |
printer_->Indent(); |
printer_->Print( |
@@ -523,7 +554,7 @@ |
PrintNestedDescriptors(message_descriptor); |
printer_->Print("\n"); |
- printer_->Print("$descriptor_name$ = descriptor.Descriptor(\n", |
+ printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n", |
"descriptor_name", |
ModuleLevelDescriptorName(message_descriptor)); |
printer_->Indent(); |
@@ -618,10 +649,10 @@ |
// Mutually recursive with PrintNestedMessages(). |
void Generator::PrintMessage( |
const Descriptor& message_descriptor) const { |
- printer_->Print("class $name$(message.Message):\n", "name", |
+ printer_->Print("class $name$(_message.Message):\n", "name", |
message_descriptor.name()); |
printer_->Indent(); |
- printer_->Print("__metaclass__ = reflection.GeneratedProtocolMessageType\n"); |
+ printer_->Print("__metaclass__ = _reflection.GeneratedProtocolMessageType\n"); |
PrintNestedMessages(message_descriptor); |
map<string, string> m; |
m["descriptor_key"] = kDescriptorKey; |
@@ -779,6 +810,7 @@ |
for (int i = 0; i < file_->message_type_count(); ++i) { |
FixForeignFieldsInNestedExtensions(*file_->message_type(i)); |
} |
+ printer_->Print("\n"); |
} |
void Generator::FixForeignFieldsInExtension( |
@@ -829,7 +861,7 @@ |
m["options"] = OptionsValue("EnumValueOptions", options_string); |
printer_->Print( |
m, |
- "descriptor.EnumValueDescriptor(\n" |
+ "_descriptor.EnumValueDescriptor(\n" |
" name='$name$', index=$index$, number=$number$,\n" |
" options=$options$,\n" |
" type=None)"); |
@@ -843,7 +875,7 @@ |
return "None"; |
} else { |
string full_class_name = "descriptor_pb2." + class_name; |
- return "descriptor._ParseOptions(" + full_class_name + "(), '" |
+ return "_descriptor._ParseOptions(" + full_class_name + "(), '" |
+ CEscape(serialized_options)+ "')"; |
} |
} |
@@ -869,7 +901,7 @@ |
// these fields in correctly after all referenced descriptors have been |
// defined and/or imported (see FixForeignFieldsInDescriptors()). |
const char field_descriptor_decl[] = |
- "descriptor.FieldDescriptor(\n" |
+ "_descriptor.FieldDescriptor(\n" |
" name='$name$', full_name='$full_name$', index=$index$,\n" |
" number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" |
" has_default_value=$has_default_value$, default_value=$default_value$,\n" |
@@ -1000,6 +1032,125 @@ |
"serialized_end", SimpleItoa(offset + sp.size())); |
} |
+namespace { |
+void PrintDescriptorOptionsFixingCode(const string& descriptor, |
+ const string& options, |
+ io::Printer* printer) { |
+ // TODO(xiaofeng): I have added a method _SetOptions() to DescriptorBase |
+ // in proto2 python runtime but it couldn't be used here because appengine |
+ // uses a snapshot version of the library in which the new method is not |
+ // yet present. After appengine has synced their runtime library, the code |
+ // below should be cleaned up to use _SetOptions(). |
+ printer->Print( |
+ "$descriptor$.has_options = True\n" |
+ "$descriptor$._options = $options$\n", |
+ "descriptor", descriptor, "options", options); |
+} |
+} // namespace |
+ |
+// Prints expressions that set the options field of all descriptors. |
+void Generator::FixAllDescriptorOptions() const { |
+ // Prints an expression that sets the file descriptor's options. |
+ string file_options = OptionsValue( |
+ "FileOptions", file_->options().SerializeAsString()); |
+ if (file_options != "None") { |
+ PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_); |
+ } |
+ // Prints expressions that set the options for all top level enums. |
+ for (int i = 0; i < file_->enum_type_count(); ++i) { |
+ const EnumDescriptor& enum_descriptor = *file_->enum_type(i); |
+ FixOptionsForEnum(enum_descriptor); |
+ } |
+ // Prints expressions that set the options for all top level extensions. |
+ for (int i = 0; i < file_->extension_count(); ++i) { |
+ const FieldDescriptor& field = *file_->extension(i); |
+ FixOptionsForField(field); |
+ } |
+ // Prints expressions that set the options for all messages, nested enums, |
+ // nested extensions and message fields. |
+ for (int i = 0; i < file_->message_type_count(); ++i) { |
+ FixOptionsForMessage(*file_->message_type(i)); |
+ } |
+} |
+ |
+// Prints expressions that set the options for an enum descriptor and its |
+// value descriptors. |
+void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const { |
+ string descriptor_name = ModuleLevelDescriptorName(enum_descriptor); |
+ string enum_options = OptionsValue( |
+ "EnumOptions", enum_descriptor.options().SerializeAsString()); |
+ if (enum_options != "None") { |
+ PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_); |
+ } |
+ for (int i = 0; i < enum_descriptor.value_count(); ++i) { |
+ const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i); |
+ string value_options = OptionsValue( |
+ "EnumValueOptions", value_descriptor.options().SerializeAsString()); |
+ if (value_options != "None") { |
+ PrintDescriptorOptionsFixingCode( |
+ StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(), |
+ value_descriptor.name().c_str()), |
+ value_options, printer_); |
+ } |
+ } |
+} |
+ |
+// Prints expressions that set the options for field descriptors (including |
+// extensions). |
+void Generator::FixOptionsForField( |
+ const FieldDescriptor& field) const { |
+ string field_options = OptionsValue( |
+ "FieldOptions", field.options().SerializeAsString()); |
+ if (field_options != "None") { |
+ string field_name; |
+ if (field.is_extension()) { |
+ if (field.extension_scope() == NULL) { |
+ // Top level extensions. |
+ field_name = field.name(); |
+ } else { |
+ field_name = FieldReferencingExpression( |
+ field.extension_scope(), field, "extensions_by_name"); |
+ } |
+ } else { |
+ field_name = FieldReferencingExpression( |
+ field.containing_type(), field, "fields_by_name"); |
+ } |
+ PrintDescriptorOptionsFixingCode(field_name, field_options, printer_); |
+ } |
+} |
+ |
+// Prints expressions that set the options for a message and all its inner |
+// types (nested messages, nested enums, extensions, fields). |
+void Generator::FixOptionsForMessage(const Descriptor& descriptor) const { |
+ // Nested messages. |
+ for (int i = 0; i < descriptor.nested_type_count(); ++i) { |
+ FixOptionsForMessage(*descriptor.nested_type(i)); |
+ } |
+ // Enums. |
+ for (int i = 0; i < descriptor.enum_type_count(); ++i) { |
+ FixOptionsForEnum(*descriptor.enum_type(i)); |
+ } |
+ // Fields. |
+ for (int i = 0; i < descriptor.field_count(); ++i) { |
+ const FieldDescriptor& field = *descriptor.field(i); |
+ FixOptionsForField(field); |
+ } |
+ // Extensions. |
+ for (int i = 0; i < descriptor.extension_count(); ++i) { |
+ const FieldDescriptor& field = *descriptor.extension(i); |
+ FixOptionsForField(field); |
+ } |
+ // Message option for this message. |
+ string message_options = OptionsValue( |
+ "MessageOptions", descriptor.options().SerializeAsString()); |
+ if (message_options != "None") { |
+ string descriptor_name = ModuleLevelDescriptorName(descriptor); |
+ PrintDescriptorOptionsFixingCode(descriptor_name, |
+ message_options, |
+ printer_); |
+ } |
+} |
+ |
} // namespace python |
} // namespace compiler |
} // namespace protobuf |