diff options
Diffstat (limited to 'src/google/protobuf/compiler/python/python_generator.cc')
-rw-r--r-- | src/google/protobuf/compiler/python/python_generator.cc | 191 |
1 files changed, 171 insertions, 20 deletions
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 9b109378..211ac70c 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -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 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, 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 @@ void PrintTopBoilerplate( // 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 @@ string StringifyDefaultValue(const FieldDescriptor& field) { 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 @@ bool Generator::Generate(const FileDescriptor* file, // 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 @@ void Generator::PrintImports() const { 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 @@ void Generator::PrintFileDescriptor() const { 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 @@ void Generator::PrintTopLevelEnums() const { 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 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { 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 @@ void Generator::PrintServiceDescriptor( 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 @@ void Generator::PrintServiceDescriptor( 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 @@ void Generator::PrintServiceDescriptor( 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::PrintServiceDescriptor( 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 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { 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 @@ void Generator::PrintMessages() const { // 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 @@ void Generator::FixForeignFieldsInExtensions() const { 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 @@ void Generator::PrintEnumValueDescriptor( 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 @@ string Generator::OptionsValue( 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 @@ void Generator::PrintFieldDescriptor( // 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 @@ void Generator::PrintSerializedPbInterval( "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 |