• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "google/protobuf/compiler/python/pyi_generator.h"
9 
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "absl/container/flat_hash_set.h"
15 #include "absl/log/absl_check.h"
16 #include "absl/log/absl_log.h"
17 #include "absl/strings/ascii.h"
18 #include "absl/strings/match.h"
19 #include "absl/strings/str_split.h"
20 #include "absl/strings/string_view.h"
21 #include "google/protobuf/compiler/code_generator.h"
22 #include "google/protobuf/compiler/python/helpers.h"
23 #include "google/protobuf/descriptor.h"
24 #include "google/protobuf/descriptor.pb.h"
25 #include "google/protobuf/io/printer.h"
26 #include "google/protobuf/io/zero_copy_stream.h"
27 
28 namespace google {
29 namespace protobuf {
30 namespace compiler {
31 namespace python {
32 
PyiGenerator()33 PyiGenerator::PyiGenerator() : file_(nullptr) {}
34 
~PyiGenerator()35 PyiGenerator::~PyiGenerator() {}
36 
37 template <typename DescriptorT>
ModuleLevelName(const DescriptorT & descriptor) const38 std::string PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const {
39   std::string name = NamePrefixedWithNestedTypes(descriptor, ".");
40   if (descriptor.file() != file_) {
41     std::string module_alias;
42     const absl::string_view filename = descriptor.file()->name();
43     if (import_map_.find(filename) == import_map_.end()) {
44       std::string module_name = ModuleName(descriptor.file()->name());
45       std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.');
46       module_alias = absl::StrCat("_", tokens.back());
47     } else {
48       module_alias = import_map_.at(filename);
49     }
50     name = absl::StrCat(module_alias, ".", name);
51   }
52   return name;
53 }
54 
PublicPackage() const55 std::string PyiGenerator::PublicPackage() const { return "google.protobuf"; }
56 
InternalPackage() const57 std::string PyiGenerator::InternalPackage() const {
58   return "google.protobuf.internal";
59 }
60 
61 struct ImportModules {
62   bool has_repeated = false;    // _containers
63   bool has_iterable = false;    // typing.Iterable
64   bool has_messages = false;    // _message
65   bool has_enums = false;       // _enum_type_wrapper
66   bool has_extendable = false;  // _python_message
67   bool has_mapping = false;     // typing.Mapping
68   bool has_optional = false;    // typing.Optional
69   bool has_union = false;       // typing.Union
70   bool has_well_known_type = false;
71 };
72 
73 // Checks whether a descriptor name matches a well-known type.
IsWellKnownType(const absl::string_view name)74 bool IsWellKnownType(const absl::string_view name) {
75   // LINT.IfChange(wktbases)
76   return (name == "google.protobuf.Any" ||
77           name == "google.protobuf.Duration" ||
78           name == "google.protobuf.FieldMask" ||
79           name == "google.protobuf.ListValue" ||
80           name == "google.protobuf.Struct" ||
81           name == "google.protobuf.Timestamp");
82   // LINT.ThenChange(//depot/google3/net/proto2/python/internal/well_known_types.py:wktbases)
83 }
84 
85 // Checks what modules should be imported for this message
86 // descriptor.
CheckImportModules(const Descriptor * descriptor,ImportModules * import_modules)87 void CheckImportModules(const Descriptor* descriptor,
88                         ImportModules* import_modules) {
89   if (descriptor->extension_range_count() > 0) {
90     import_modules->has_extendable = true;
91   }
92   if (descriptor->enum_type_count() > 0) {
93     import_modules->has_enums = true;
94   }
95   if (IsWellKnownType(descriptor->full_name())) {
96     import_modules->has_well_known_type = true;
97   }
98   for (int i = 0; i < descriptor->field_count(); ++i) {
99     const FieldDescriptor* field = descriptor->field(i);
100     if (IsPythonKeyword(field->name())) {
101       continue;
102     }
103     import_modules->has_optional = true;
104     if (field->is_repeated()) {
105       import_modules->has_repeated = true;
106     }
107     if (field->is_map()) {
108       import_modules->has_mapping = true;
109       const FieldDescriptor* value_des = field->message_type()->field(1);
110       if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
111           value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
112         import_modules->has_union = true;
113       }
114     } else {
115       if (field->is_repeated()) {
116         import_modules->has_iterable = true;
117       }
118       if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
119         import_modules->has_union = true;
120         import_modules->has_mapping = true;
121       }
122       if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
123         import_modules->has_union = true;
124       }
125     }
126   }
127   for (int i = 0; i < descriptor->nested_type_count(); ++i) {
128     CheckImportModules(descriptor->nested_type(i), import_modules);
129   }
130 }
131 
PrintImportForDescriptor(const FileDescriptor & desc,absl::flat_hash_set<std::string> * seen_aliases,bool * has_importlib) const132 void PyiGenerator::PrintImportForDescriptor(
133     const FileDescriptor& desc, absl::flat_hash_set<std::string>* seen_aliases,
134     bool* has_importlib) const {
135   const absl::string_view filename = desc.name();
136   std::string module_name_owned = StrippedModuleName(filename);
137   absl::string_view module_name(module_name_owned);
138   size_t last_dot_pos = module_name.rfind('.');
139   std::string alias = absl::StrCat("_", module_name.substr(last_dot_pos + 1));
140   // Generate a unique alias by adding _1 suffixes until we get an unused alias.
141   while (seen_aliases->find(alias) != seen_aliases->end()) {
142     absl::StrAppend(&alias, "_1");
143   }
144   if (ContainsPythonKeyword(module_name)) {
145     if (*has_importlib == false) {
146       printer_->Print("import importlib\n");
147       *has_importlib = true;
148     }
149     printer_->Print("$alias$ = importlib.import_module('$name$')\n", "alias",
150                     alias, "name", module_name);
151   } else {
152     std::string import_statement;
153     if (last_dot_pos == std::string::npos) {
154       import_statement = absl::StrCat("import ", module_name);
155     } else {
156       import_statement =
157           absl::StrCat("from ", module_name.substr(0, last_dot_pos), " import ",
158                        module_name.substr(last_dot_pos + 1));
159     }
160     printer_->Print("$statement$ as $alias$\n", "statement", import_statement,
161                     "alias", alias);
162     import_map_[filename] = alias;
163     seen_aliases->insert(alias);
164   }
165 }
166 
PrintImports() const167 void PyiGenerator::PrintImports() const {
168   // Prints imported dependent _pb2 files.
169   absl::flat_hash_set<std::string> seen_aliases;
170   bool has_importlib = false;
171   for (int i = 0; i < file_->dependency_count(); ++i) {
172     const FileDescriptor* dep = file_->dependency(i);
173     if (strip_nonfunctional_codegen_ && IsKnownFeatureProto(dep->name())) {
174       continue;
175     }
176     PrintImportForDescriptor(*dep, &seen_aliases, &has_importlib);
177     for (int j = 0; j < dep->public_dependency_count(); ++j) {
178       PrintImportForDescriptor(*dep->public_dependency(j), &seen_aliases,
179                                &has_importlib);
180     }
181   }
182 
183   // Checks what modules should be imported.
184   ImportModules import_modules;
185   if (file_->message_type_count() > 0) {
186     import_modules.has_messages = true;
187   }
188   if (file_->enum_type_count() > 0) {
189     import_modules.has_enums = true;
190   }
191   if (!opensource_runtime_ && file_->service_count() > 0) {
192     import_modules.has_optional = true;
193     import_modules.has_union = true;
194   }
195   for (int i = 0; i < file_->message_type_count(); i++) {
196     CheckImportModules(file_->message_type(i), &import_modules);
197   }
198 
199   // Prints modules (e.g. _containers, _messages, typing) that are
200   // required in the proto file.
201   if (import_modules.has_repeated) {
202     printer_->Print(
203         "from $internal_package$ import containers as _containers\n",
204         "internal_package", InternalPackage());
205   }
206   if (import_modules.has_enums) {
207     printer_->Print(
208         "from $internal_package$ import enum_type_wrapper as "
209         "_enum_type_wrapper\n",
210         "internal_package", InternalPackage());
211   }
212   if (import_modules.has_extendable) {
213     printer_->Print(
214         "from $internal_package$ import python_message as _python_message\n",
215         "internal_package", InternalPackage());
216   }
217   if (import_modules.has_well_known_type) {
218     printer_->Print(
219         "from $internal_package$ import well_known_types as "
220         "_well_known_types\n",
221         "internal_package", InternalPackage());
222   }
223   printer_->Print("from $public_package$ import descriptor as _descriptor\n",
224                   "public_package", PublicPackage());
225   if (import_modules.has_messages) {
226     printer_->Print("from $public_package$ import message as _message\n",
227                     "public_package", PublicPackage());
228   }
229   if (opensource_runtime_) {
230     if (HasGenericServices(file_)) {
231       printer_->Print("from $public_package$ import service as _service\n",
232                       "public_package", PublicPackage());
233     }
234   } else {
235     if (file_->service_count() > 0) {
236       printer_->Print(
237           "from google3.net.rpc.python import proto_python_api_2_stub as "
238           "_proto_python_api_2_stub\n"
239           "from google3.net.rpc.python import pywraprpc as _pywraprpc\n"
240           "from google3.net.rpc.python import rpcserver as _rpcserver\n");
241     }
242   }
243   printer_->Print("from typing import ");
244   if (!opensource_runtime_ && file_->service_count() > 0) {
245     printer_->Print("Any as _Any, ");
246   }
247   printer_->Print("ClassVar as _ClassVar");
248   if (import_modules.has_iterable) {
249     printer_->Print(", Iterable as _Iterable");
250   }
251   if (import_modules.has_mapping) {
252     printer_->Print(", Mapping as _Mapping");
253   }
254   if (import_modules.has_optional) {
255     printer_->Print(", Optional as _Optional");
256   }
257   if (import_modules.has_union) {
258     printer_->Print(", Union as _Union");
259   }
260   printer_->Print("\n");
261 
262   // Public imports
263   for (int i = 0; i < file_->public_dependency_count(); ++i) {
264     const FileDescriptor* public_dep = file_->public_dependency(i);
265     std::string module_name = StrippedModuleName(public_dep->name());
266     // Top level messages in public imports
267     for (int i = 0; i < public_dep->message_type_count(); ++i) {
268       printer_->Print(
269           "from $module$ import $message_class$ as $message_class$\n", "module",
270           module_name, "message_class", public_dep->message_type(i)->name());
271     }
272     // Top level enums for public imports
273     for (int i = 0; i < public_dep->enum_type_count(); ++i) {
274       printer_->Print("from $module$ import $enum_class$ as $enum_class$\n",
275                       "module", module_name, "enum_class",
276                       public_dep->enum_type(i)->name());
277     }
278   }
279 printer_->Print("\n");
280 }
281 
282 // Annotate wrapper for debugging purposes
283 // Print a message after Annotate to see what is annotated.
284 template <typename DescriptorT>
Annotate(const std::string & label,const DescriptorT * descriptor) const285 void PyiGenerator::Annotate(const std::string& label,
286                             const DescriptorT* descriptor) const {
287 printer_->Annotate(label.c_str(), descriptor);
288 }
289 
PrintEnum(const EnumDescriptor & enum_descriptor) const290 void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const {
291   const absl::string_view enum_name = enum_descriptor.name();
292   printer_->Print(
293       "class $enum_name$(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):\n"
294       "    __slots__ = ()\n",
295       "enum_name", enum_name);
296   Annotate("enum_name", &enum_descriptor);
297   printer_->Indent();
298   PrintEnumValues(enum_descriptor, /* is_classvar = */ true);
299   printer_->Outdent();
300 }
301 
PrintEnumValues(const EnumDescriptor & enum_descriptor,bool is_classvar) const302 void PyiGenerator::PrintEnumValues(const EnumDescriptor& enum_descriptor,
303                                    bool is_classvar) const {
304   // enum values
305   std::string module_enum_name = ModuleLevelName(enum_descriptor);
306   for (int j = 0; j < enum_descriptor.value_count(); ++j) {
307     const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j);
308     if (is_classvar) {
309       printer_->Print("$name$: _ClassVar[$module_enum_name$]\n", "name",
310                       value_descriptor->name(), "module_enum_name",
311                       module_enum_name);
312     } else {
313       printer_->Print("$name$: $module_enum_name$\n", "name",
314                       value_descriptor->name(), "module_enum_name",
315                       module_enum_name);
316     }
317     Annotate("name", value_descriptor);
318   }
319 }
320 
PrintTopLevelEnums() const321 void PyiGenerator::PrintTopLevelEnums() const {
322   for (int i = 0; i < file_->enum_type_count(); ++i) {
323     printer_->Print("\n");
324     PrintEnum(*file_->enum_type(i));
325   }
326 }
327 
328 template <typename DescriptorT>
PrintExtensions(const DescriptorT & descriptor) const329 void PyiGenerator::PrintExtensions(const DescriptorT& descriptor) const {
330   for (int i = 0; i < descriptor.extension_count(); ++i) {
331     const FieldDescriptor* extension_field = descriptor.extension(i);
332     std::string constant_name =
333         absl::StrCat(extension_field->name(), "_FIELD_NUMBER");
334     absl::AsciiStrToUpper(&constant_name);
335     printer_->Print("$constant_name$: _ClassVar[int]\n",
336                     "constant_name", constant_name);
337     printer_->Print("$name$: _descriptor.FieldDescriptor\n",
338                     "name", extension_field->name());
339     Annotate("name", extension_field);
340   }
341 }
342 
343 // Returns the string format of a field's cpp_type
GetFieldType(const FieldDescriptor & field_des,const Descriptor & containing_des) const344 std::string PyiGenerator::GetFieldType(
345     const FieldDescriptor& field_des, const Descriptor& containing_des) const {
346   switch (field_des.cpp_type()) {
347     case FieldDescriptor::CPPTYPE_INT32:
348     case FieldDescriptor::CPPTYPE_UINT32:
349     case FieldDescriptor::CPPTYPE_INT64:
350     case FieldDescriptor::CPPTYPE_UINT64:
351       return "int";
352     case FieldDescriptor::CPPTYPE_DOUBLE:
353     case FieldDescriptor::CPPTYPE_FLOAT:
354       return "float";
355     case FieldDescriptor::CPPTYPE_BOOL:
356       return "bool";
357     case FieldDescriptor::CPPTYPE_ENUM:
358       return ModuleLevelName(*field_des.enum_type());
359     case FieldDescriptor::CPPTYPE_STRING:
360       if (field_des.type() == FieldDescriptor::TYPE_STRING) {
361         return "str";
362       } else {
363         return "bytes";
364       }
365     case FieldDescriptor::CPPTYPE_MESSAGE: {
366       // If the field is inside a nested message and the nested message has the
367       // same name as a top-level message, then we need to prefix the field type
368       // with the module name for disambiguation.
369       std::string name = ModuleLevelName(*field_des.message_type());
370       if ((containing_des.containing_type() != nullptr &&
371            name == containing_des.name())) {
372         std::string module = ModuleName(field_des.file()->name());
373         name = absl::StrCat(module, ".", name);
374       }
375       return name;
376     }
377     default:
378       ABSL_LOG(FATAL) << "Unsupported field type.";
379   }
380   return "";
381 }
382 
PrintMessage(const Descriptor & message_descriptor,bool is_nested) const383 void PyiGenerator::PrintMessage(
384     const Descriptor& message_descriptor, bool is_nested) const {
385   if (!is_nested) {
386     printer_->Print("\n");
387   }
388   const absl::string_view class_name = message_descriptor.name();
389   std::string extra_base;
390   // A well-known type needs to inherit from its corresponding base class in
391   // net/proto2/python/internal/well_known_types.
392   if (IsWellKnownType(message_descriptor.full_name())) {
393     extra_base =
394         absl::StrCat(", _well_known_types.", message_descriptor.name());
395   } else {
396     extra_base = "";
397   }
398   printer_->Print("class $class_name$(_message.Message$extra_base$):\n",
399                   "class_name", class_name, "extra_base", extra_base);
400   Annotate("class_name", &message_descriptor);
401   printer_->Indent();
402 
403   // Prints slots
404   printer_->Print("__slots__ = (");
405   int items_printed = 0;
406   for (int i = 0; i < message_descriptor.field_count(); ++i) {
407     const FieldDescriptor* field_des = message_descriptor.field(i);
408     if (IsPythonKeyword(field_des->name())) {
409       continue;
410     }
411     if (items_printed > 0) {
412       printer_->Print(", ");
413     }
414     ++items_printed;
415     printer_->Print("\"$field_name$\"", "field_name", field_des->name());
416   }
417   printer_->Print(items_printed == 1 ? ",)\n" : ")\n");
418 
419   // Prints Extensions for extendable messages
420   if (message_descriptor.extension_range_count() > 0) {
421     printer_->Print("Extensions: _python_message._ExtensionDict\n");
422   }
423 
424   // Prints nested enums
425   for (int i = 0; i < message_descriptor.enum_type_count(); ++i) {
426     PrintEnum(*message_descriptor.enum_type(i));
427     PrintEnumValues(*message_descriptor.enum_type(i));
428   }
429 
430   // Prints nested messages
431   for (int i = 0; i < message_descriptor.nested_type_count(); ++i) {
432     PrintMessage(*message_descriptor.nested_type(i), true);
433   }
434 
435   PrintExtensions(message_descriptor);
436 
437   // Prints field number
438   for (int i = 0; i < message_descriptor.field_count(); ++i) {
439     const FieldDescriptor& field_des = *message_descriptor.field(i);
440     printer_->Print(
441         "$field_number_name$: _ClassVar[int]\n", "field_number_name",
442         absl::StrCat(absl::AsciiStrToUpper(field_des.name()), "_FIELD_NUMBER"));
443   }
444   // Prints field name and type
445   for (int i = 0; i < message_descriptor.field_count(); ++i) {
446     const FieldDescriptor& field_des = *message_descriptor.field(i);
447     if (IsPythonKeyword(field_des.name())) {
448       continue;
449     }
450     std::string field_type = "";
451     if (field_des.is_map()) {
452       const FieldDescriptor* key_des = field_des.message_type()->field(0);
453       const FieldDescriptor* value_des = field_des.message_type()->field(1);
454       field_type =
455           absl::StrCat(value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
456                            ? "_containers.MessageMap["
457                            : "_containers.ScalarMap[",
458                        GetFieldType(*key_des, message_descriptor), ", ",
459                        GetFieldType(*value_des, message_descriptor));
460     } else {
461       if (field_des.is_repeated()) {
462         field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE
463                           ? "_containers.RepeatedCompositeFieldContainer["
464                           : "_containers.RepeatedScalarFieldContainer[");
465       }
466       field_type += GetFieldType(field_des, message_descriptor);
467     }
468 
469     if (field_des.is_repeated()) {
470       absl::StrAppend(&field_type, "]");
471     }
472     printer_->Print("$name$: $type$\n",
473                     "name", field_des.name(), "type", field_type);
474     Annotate("name", &field_des);
475   }
476 
477   // Prints __init__
478   printer_->Print("def __init__(self");
479   bool has_key_words = false;
480   bool is_first = true;
481   for (int i = 0; i < message_descriptor.field_count(); ++i) {
482     const FieldDescriptor* field_des = message_descriptor.field(i);
483     if (IsPythonKeyword(field_des->name())) {
484       has_key_words = true;
485       continue;
486     }
487     std::string field_name = std::string(field_des->name());
488     if (is_first && field_name == "self") {
489       // See b/144146793 for an example of real code that generates a (self,
490       // self) method signature. Since repeating a parameter name is illegal in
491       // Python, we rename the duplicate self.
492       field_name = "self_";
493     }
494     is_first = false;
495     printer_->Print(", $field_name$: ", "field_name", field_name);
496     Annotate("field_name", field_des);
497     if (field_des->is_repeated() ||
498         field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
499       printer_->Print("_Optional[");
500     }
501     if (field_des->is_map()) {
502       const Descriptor* map_entry = field_des->message_type();
503       printer_->Print(
504           "_Mapping[$key_type$, $value_type$]", "key_type",
505           GetFieldType(*map_entry->field(0), message_descriptor),
506           "value_type",
507           GetFieldType(*map_entry->field(1), message_descriptor));
508     } else {
509       if (field_des->is_repeated()) {
510         printer_->Print("_Iterable[");
511       }
512       if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
513         printer_->Print(
514             "_Union[$type_name$, _Mapping]", "type_name",
515             GetFieldType(*field_des, message_descriptor));
516       } else {
517         if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
518           printer_->Print("_Union[$type_name$, str]", "type_name",
519                           ModuleLevelName(*field_des->enum_type()));
520         } else {
521           printer_->Print(
522               "$type_name$", "type_name",
523               GetFieldType(*field_des, message_descriptor));
524         }
525       }
526       if (field_des->is_repeated()) {
527         printer_->Print("]");
528       }
529     }
530     if (field_des->is_repeated() ||
531         field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) {
532       printer_->Print("]");
533     }
534     printer_->Print(" = ...");
535   }
536   if (has_key_words) {
537     printer_->Print(", **kwargs");
538   }
539   printer_->Print(") -> None: ...\n");
540   printer_->Outdent();
541 }
542 
PrintMessages() const543 void PyiGenerator::PrintMessages() const {
544   // Deterministically order the descriptors.
545   for (int i = 0; i < file_->message_type_count(); ++i) {
546     PrintMessage(*file_->message_type(i), false);
547   }
548 }
549 
PrintServices() const550 void PyiGenerator::PrintServices() const {
551   // Prints $Service$ and $Service$_Stub classes
552   for (int i = 0; i < file_->service_count(); ++i) {
553     printer_->Print("\n");
554     printer_->Print(
555         "class $service_name$(_service.service): ...\n\n"
556         "class $service_name$_Stub($service_name$): ...\n",
557         "service_name", file_->service(i)->name());
558   }
559 }
560 
561 
Generate(const FileDescriptor * file,const std::string & parameter,GeneratorContext * context,std::string * error) const562 bool PyiGenerator::Generate(const FileDescriptor* file,
563                             const std::string& parameter,
564                             GeneratorContext* context,
565                             std::string* error) const {
566   absl::MutexLock lock(&mutex_);
567   import_map_.clear();
568   // Calculate file name.
569   file_ = file;
570   // In google3, devtools/python/bazel/pytype/pytype_impl.bzl uses --pyi_out to
571   // directly set the output file name.
572   std::vector<std::pair<std::string, std::string> > options;
573   ParseGeneratorParameter(parameter, &options);
574 
575   std::string filename;
576   bool annotate_code = false;
577   strip_nonfunctional_codegen_ = false;
578   for (const std::pair<std::string, std::string>& option : options) {
579     if (option.first == "annotate_code") {
580       annotate_code = true;
581     } else if (absl::EndsWith(option.first, ".pyi")) {
582       filename = option.first;
583     } else if (option.first == "experimental_strip_nonfunctional_codegen") {
584       strip_nonfunctional_codegen_ = true;
585     } else {
586       *error = absl::StrCat("Unknown generator option: ", option.first);
587       return false;
588     }
589   }
590 
591   if (filename.empty()) {
592     filename = GetFileName(file, ".pyi");
593   }
594 
595   std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
596   ABSL_CHECK(output.get());
597   GeneratedCodeInfo annotations;
598   io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
599       &annotations);
600   io::Printer::Options printer_opt(
601       '$', annotate_code ? &annotation_collector : nullptr);
602   printer_opt.spaces_per_indent = 4;
603   io::Printer printer(output.get(), printer_opt);
604   printer_ = &printer;
605 
606   PrintImports();
607   printer_->Print("DESCRIPTOR: _descriptor.FileDescriptor\n");
608 
609   // Prints extensions and enums from imports.
610   for (int i = 0; i < file_->public_dependency_count(); ++i) {
611     const FileDescriptor* public_dep = file_->public_dependency(i);
612     PrintExtensions(*public_dep);
613     for (int i = 0; i < public_dep->enum_type_count(); ++i) {
614       const EnumDescriptor* enum_descriptor = public_dep->enum_type(i);
615       PrintEnumValues(*enum_descriptor);
616     }
617   }
618 
619   PrintTopLevelEnums();
620   // Prints top level enum values
621   for (int i = 0; i < file_->enum_type_count(); ++i) {
622     PrintEnumValues(*file_->enum_type(i));
623   }
624   // Prints top level Extensions
625   PrintExtensions(*file_);
626   PrintMessages();
627 
628   if (opensource_runtime_ && HasGenericServices(file)) {
629     PrintServices();
630   }
631   return true;
632 }
633 
634 }  // namespace python
635 }  // namespace compiler
636 }  // namespace protobuf
637 }  // namespace google
638